test/unittest_schema.py
changeset 0 b97547f5f1fa
child 13 bae30087db21
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """unit tests for module cubicweb.schema"""
       
     2 
       
     3 import sys
       
     4 from os.path import join, isabs, basename, dirname
       
     5 
       
     6 from logilab.common.testlib import TestCase, unittest_main
       
     7 
       
     8 from rql import RQLSyntaxError
       
     9 
       
    10 from yams import BadSchemaDefinition
       
    11 from yams.constraints import SizeConstraint, StaticVocabularyConstraint
       
    12 from yams.buildobjs import RelationDefinition, EntityType, RelationType
       
    13 
       
    14 from cubicweb.schema import CubicWebSchema, CubicWebEntitySchema, \
       
    15      RQLConstraint, CubicWebSchemaLoader, ERQLExpression, RRQLExpression, \
       
    16      normalize_expression
       
    17 from cubicweb.devtools import TestServerConfiguration as TestConfiguration
       
    18 
       
    19 DATADIR = join(dirname(__file__), 'data')
       
    20 
       
    21 # build a dummy schema ########################################################
       
    22 
       
    23 
       
    24 PERSONNE_PERMISSIONS =  {
       
    25     'read':   ('managers', 'users', 'guests'),
       
    26     'update': ('managers', 'owners'),
       
    27     'add':    ('managers', ERQLExpression('X travaille S, S owned_by U')),
       
    28     'delete': ('managers', 'owners',),
       
    29     }
       
    30 
       
    31 CONCERNE_PERMISSIONS = {
       
    32     'read':   ('managers', 'users', 'guests'),
       
    33     'add':    ('managers', RRQLExpression('U has_update_permission S')),
       
    34     'delete': ('managers', RRQLExpression('O owned_by U')),
       
    35     }
       
    36 
       
    37 schema = CubicWebSchema('Test Schema')
       
    38 enote = schema.add_entity_type(EntityType('Note'))
       
    39 eaffaire = schema.add_entity_type(EntityType('Affaire'))
       
    40 eperson = schema.add_entity_type(EntityType('Personne', permissions=PERSONNE_PERMISSIONS))
       
    41 esociete = schema.add_entity_type(EntityType('Societe'))
       
    42 
       
    43 RELS = (
       
    44     # attribute relations
       
    45     ('Note date String'),
       
    46     ('Note type String'),
       
    47     ('Affaire sujet String'),
       
    48     ('Affaire ref String'),
       
    49     ('Personne nom String'),
       
    50     ('Personne prenom String'),
       
    51     ('Personne sexe String'),
       
    52     ('Personne tel Int'),
       
    53     ('Personne fax Int'),
       
    54     ('Personne datenaiss Date'),
       
    55     ('Personne TEST Boolean'),
       
    56     ('Personne promo String'),
       
    57     # real relations
       
    58     ('Personne  travaille Societe'),
       
    59     ('Personne  evaluee   Note'),
       
    60     ('Societe evaluee   Note'),
       
    61     ('Personne  concerne  Affaire'),
       
    62     ('Personne  concerne  Societe'),
       
    63     ('Affaire Concerne  Societe'),
       
    64     )
       
    65 done = {}
       
    66 for rel in RELS:
       
    67     _from, _type, _to = rel.split()
       
    68     if not _type.lower() in done:
       
    69         if _type == 'concerne':
       
    70             schema.add_relation_type(RelationType(_type, permissions=CONCERNE_PERMISSIONS))
       
    71         else:
       
    72             schema.add_relation_type(RelationType(_type))
       
    73         done[_type.lower()] = True
       
    74     schema.add_relation_def(RelationDefinition(_from, _type, _to))
       
    75 
       
    76 class CubicWebSchemaTC(TestCase):
       
    77 
       
    78     def test_normalize(self):
       
    79         """test that entities, relations and attributes name are normalized
       
    80         """
       
    81         self.assertEqual(esociete.type, 'Societe')
       
    82         self.assertEqual(schema.has_relation('TEST'), 0)
       
    83         self.assertEqual(schema.has_relation('test'), 1)
       
    84         self.assertEqual(eperson.subject_relation('test').type, 'test')
       
    85         self.assertEqual(schema.has_relation('Concerne'), 0)
       
    86         self.assertEqual(schema.has_relation('concerne'), 1)
       
    87         self.assertEqual(schema.rschema('concerne').type, 'concerne')
       
    88 
       
    89     def test_entity_perms(self):
       
    90         eperson.set_default_groups()
       
    91         self.assertEqual(eperson.get_groups('read'), set(('managers', 'users', 'guests')))
       
    92         self.assertEqual(eperson.get_groups('update'), set(('managers', 'owners',)))
       
    93         self.assertEqual(eperson.get_groups('delete'), set(('managers', 'owners')))
       
    94         self.assertEqual(eperson.get_groups('add'), set(('managers',)))
       
    95         self.assertEqual([str(e) for e in eperson.get_rqlexprs('add')],
       
    96                          ['Any X WHERE X travaille S, S owned_by U, X eid %(x)s, U eid %(u)s'])
       
    97         eperson.set_groups('read', ('managers',))
       
    98         self.assertEqual(eperson.get_groups('read'), set(('managers',)))
       
    99         
       
   100     def test_relation_perms(self):
       
   101         rconcerne = schema.rschema('concerne')
       
   102         rconcerne.set_default_groups()
       
   103         self.assertEqual(rconcerne.get_groups('read'), set(('managers', 'users', 'guests')))
       
   104         self.assertEqual(rconcerne.get_groups('delete'), set(('managers',)))
       
   105         self.assertEqual(rconcerne.get_groups('add'), set(('managers', )))
       
   106         rconcerne.set_groups('read', ('managers',))
       
   107         self.assertEqual(rconcerne.get_groups('read'), set(('managers',)))
       
   108         self.assertEqual([str(e) for e in rconcerne.get_rqlexprs('add')],
       
   109                          ['Any S WHERE U has_update_permission S, S eid %(s)s, U eid %(u)s'])
       
   110 
       
   111     def test_erqlexpression(self):
       
   112         self.assertRaises(RQLSyntaxError, ERQLExpression, '1')
       
   113         expr = ERQLExpression('X travaille S, S owned_by U')
       
   114         self.assertEquals(str(expr), 'Any X WHERE X travaille S, S owned_by U, X eid %(x)s, U eid %(u)s')
       
   115         
       
   116     def test_rrqlexpression(self):
       
   117         self.assertRaises(Exception, RRQLExpression, '1')
       
   118         self.assertRaises(RQLSyntaxError, RRQLExpression, 'O X Y')
       
   119         expr = RRQLExpression('U has_update_permission O')
       
   120         self.assertEquals(str(expr), 'Any O WHERE U has_update_permission O, O eid %(o)s, U eid %(u)s')
       
   121         
       
   122 
       
   123 loader = CubicWebSchemaLoader()
       
   124 config = TestConfiguration('data')
       
   125 config.bootstrap_cubes()
       
   126 loader.lib_directory = config.schemas_lib_dir()
       
   127     
       
   128 class SQLSchemaReaderClassTest(TestCase):
       
   129 
       
   130     def test_knownValues_include_schema_files(self):
       
   131         schema_files = loader.include_schema_files('Bookmark')
       
   132         for file in schema_files:
       
   133             self.assert_(isabs(file))
       
   134         self.assertListEquals([basename(f) for f in schema_files], ['Bookmark.py'])
       
   135 
       
   136     def test_knownValues_load_schema(self):
       
   137         """read an url and return a Schema instance"""
       
   138         schema = loader.load(config)
       
   139         self.assert_(isinstance(schema, CubicWebSchema))
       
   140         self.assertEquals(schema.name, 'data')
       
   141         entities = [str(e) for e in schema.entities()]
       
   142         entities.sort()
       
   143         expected_entities = ['Bookmark', 'Boolean', 'Bytes', 'Card', 
       
   144                              'Date', 'Datetime', 'Decimal',
       
   145                              'EConstraint', 'EConstraintType', 'EEType',
       
   146                              'EFRDef', 'EGroup', 'EmailAddress', 'ENFRDef',
       
   147                              'EPermission', 'EProperty', 'ERType', 'EUser',
       
   148                              'Float', 'Int', 'Interval', 
       
   149                              'Password', 
       
   150                              'RQLExpression', 
       
   151                              'State', 'String', 'Time', 
       
   152                              'Transition', 'TrInfo']
       
   153         self.assertListEquals(entities, sorted(expected_entities))
       
   154         relations = [str(r) for r in schema.relations()]
       
   155         relations.sort()
       
   156         expected_relations = ['add_permission', 'address', 'alias',
       
   157                               'allowed_transition', 'bookmarked_by', 'canonical',
       
   158 
       
   159                               'cardinality', 'comment', 'comment_format', 
       
   160                               'composite', 'condition', 'constrained_by', 'content',
       
   161                               'content_format', 'created_by', 'creation_date', 'cstrtype',
       
   162 
       
   163                               'defaultval', 'delete_permission', 'description',
       
   164                               'description_format', 'destination_state',
       
   165 
       
   166                               'eid', 'expression', 'exprtype',
       
   167 
       
   168                               'final', 'firstname', 'for_user',
       
   169                               'from_entity', 'from_state', 'fulltext_container', 'fulltextindexed',
       
   170 
       
   171                               'has_text', 
       
   172                               'identical_to', 'identity', 'in_group', 'in_state', 'indexed',
       
   173                               'initial_state', 'inlined', 'internationalizable', 'is', 'is_instance_of',
       
   174 
       
   175                               'label', 'last_login_time', 'login',
       
   176 
       
   177                               'mainvars', 'meta', 'modification_date',
       
   178 
       
   179                               'name', 
       
   180 
       
   181                               'ordernum', 'owned_by',
       
   182 
       
   183                               'path', 'pkey', 'primary_email', 
       
   184 
       
   185                               'read_permission', 'relation_type', 'require_group',
       
   186                               
       
   187                               'specializes', 'state_of', 'surname', 'symetric', 'synopsis',
       
   188 
       
   189                               'title', 'to_entity', 'to_state', 'transition_of',
       
   190 
       
   191                               'upassword', 'update_permission', 'use_email',
       
   192 
       
   193                               'value', 
       
   194 
       
   195                               'wf_info_for', 'wikiid']
       
   196     
       
   197         self.assertListEquals(relations, expected_relations)
       
   198 
       
   199         eschema = schema.eschema('EUser')
       
   200         rels = sorted(str(r) for r in eschema.subject_relations())
       
   201         self.assertListEquals(rels, ['created_by', 'creation_date', 'eid',
       
   202                                      'firstname', 'has_text', 'identity',
       
   203                                      'in_group', 'in_state', 'is',
       
   204                                      'is_instance_of', 'last_login_time',
       
   205                                      'login', 'modification_date', 'owned_by',
       
   206                                      'primary_email', 'surname', 'upassword',
       
   207                                      'use_email'])
       
   208         rels = sorted(r.type for r in eschema.object_relations())
       
   209         self.assertListEquals(rels, ['bookmarked_by', 'created_by', 'for_user',
       
   210                                      'identity', 'owned_by', 'wf_info_for'])
       
   211         rschema = schema.rschema('relation_type')
       
   212         properties = rschema.rproperties('EFRDef', 'ERType')
       
   213         self.assertEquals(properties['cardinality'], '1*')
       
   214         constraints = properties['constraints']
       
   215         self.failUnlessEqual(len(constraints), 1, constraints)
       
   216         constraint = constraints[0]
       
   217         self.failUnless(isinstance(constraint, RQLConstraint))
       
   218         self.failUnlessEqual(constraint.restriction, 'O final TRUE')
       
   219 
       
   220     def test_fulltext_container(self):
       
   221         schema = loader.load(config)
       
   222         self.failUnless('has_text' in schema['EUser'].subject_relations())
       
   223         self.failIf('has_text' in schema['EmailAddress'].subject_relations())
       
   224 
       
   225 
       
   226 class BadSchemaRQLExprTC(TestCase):
       
   227     def setUp(self):
       
   228         self.loader = CubicWebSchemaLoader()
       
   229         self.loader.defined = {}
       
   230         self.loader._instantiate_handlers()
       
   231 
       
   232     def _test(self, schemafile, msg):
       
   233         self.loader.handle_file(join(DATADIR, schemafile))
       
   234         ex = self.assertRaises(BadSchemaDefinition,
       
   235                                self.loader._build_schema, 'toto', False)
       
   236         self.assertEquals(str(ex), msg)
       
   237         
       
   238     def test_rrqlexpr_on_etype(self):
       
   239         self._test('rrqlexpr_on_eetype.py', "can't use RRQLExpression on an entity type, use an ERQLExpression (ToTo)")
       
   240         
       
   241     def test_erqlexpr_on_rtype(self):
       
   242         self._test('erqlexpr_on_ertype.py', "can't use ERQLExpression on a relation type, use a RRQLExpression (toto)")
       
   243         
       
   244     def test_rqlexpr_on_rtype_read(self):
       
   245         self._test('rqlexpr_on_ertype_read.py', "can't use rql expression for read permission of a relation type (toto)")
       
   246         
       
   247     def test_rrqlexpr_on_attr(self):
       
   248         self._test('rrqlexpr_on_attr.py', "can't use RRQLExpression on a final relation type (eg attribute relation), use an ERQLExpression (attr)")
       
   249 
       
   250 
       
   251 class NormalizeExpressionTC(TestCase):
       
   252 
       
   253     def test(self):
       
   254         self.assertEquals(normalize_expression('X  bla Y,Y blur Z  ,  Z zigoulou   X '),
       
   255                                                'X bla Y, Y blur Z, Z zigoulou X')
       
   256 
       
   257 if __name__ == '__main__':
       
   258     unittest_main()