|
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() |