[CWEP002 migration] properly raise exception on (add|drop)_relation_definition for computed relation
Related to #3546717
--- a/server/migractions.py Fri Jun 27 12:00:17 2014 +0200
+++ b/server/migractions.py Thu Aug 28 07:49:31 2014 +0200
@@ -1086,6 +1086,9 @@
schema definition file
"""
rschema = self.fs_schema.rschema(rtype)
+ if rschema.rule:
+ raise ExecutionError('Cannot add a relation definition for a '
+ 'computed relation (%s)' % rschema)
if not rtype in self.repo.schema:
self.cmd_add_relation_type(rtype, addrdef=False, commit=True)
if (subjtype, objtype) in self.repo.schema.rschema(rtype).rdefs:
@@ -1113,6 +1116,9 @@
def cmd_drop_relation_definition(self, subjtype, rtype, objtype, commit=True):
"""unregister an existing relation definition"""
rschema = self.repo.schema.rschema(rtype)
+ if rschema.rule:
+ raise ExecutionError('Cannot drop a relation definition for a '
+ 'computed relation (%s)' % rschema)
# unregister the definition from CWAttribute or CWRelation
if rschema.final:
etype = 'CWAttribute'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/datacomputed/migratedapp/schema.py Thu Aug 28 07:49:31 2014 +0200
@@ -0,0 +1,51 @@
+# copyright 2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from yams.buildobjs import EntityType, RelationDefinition, ComputedRelation
+
+
+class Employee(EntityType):
+ pass
+
+
+class employees(RelationDefinition):
+ subject = 'Company'
+ object = 'Employee'
+
+
+class associates(RelationDefinition):
+ subject = 'Company'
+ object = 'Employee'
+
+
+class works_for(ComputedRelation):
+ rule = 'O employees S, NOT EXISTS (O associates S)'
+
+
+class Company(EntityType):
+ pass
+
+
+class Note(EntityType):
+ pass
+
+
+class concerns(RelationDefinition):
+ subject = 'Note'
+ object = 'Employee'
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/datacomputed/schema.py Thu Aug 28 07:49:31 2014 +0200
@@ -0,0 +1,50 @@
+# copyright 2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from yams.buildobjs import EntityType, RelationDefinition, ComputedRelation
+
+
+class Employee(EntityType):
+ pass
+
+
+class employees(RelationDefinition):
+ subject = 'Company'
+ object = 'Employee'
+
+
+class associates(RelationDefinition):
+ subject = 'Company'
+ object = 'Employee'
+
+
+class Company(EntityType):
+ pass
+
+
+class Note(EntityType):
+ pass
+
+
+class concerns(RelationDefinition):
+ subject = 'Note'
+ object = 'Employee'
+
+
+class notes(ComputedRelation):
+ rule = 'S employees E, O concerns E'
--- a/server/test/unittest_migractions.py Fri Jun 27 12:00:17 2014 +0200
+++ b/server/test/unittest_migractions.py Thu Aug 28 07:49:31 2014 +0200
@@ -18,46 +18,50 @@
"""unit tests for module cubicweb.server.migractions"""
from datetime import date
-from os.path import join
+import os.path as osp
from contextlib import contextmanager
from logilab.common.testlib import unittest_main, Tags, tag
from yams.constraints import UniqueConstraint
-from cubicweb import ConfigurationError, ValidationError
+from cubicweb import ConfigurationError, ValidationError, ExecutionError
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.server.sqlutils import SQL_PREFIX
from cubicweb.server.migractions import ServerMigrationHelper
import cubicweb.devtools
+
+HERE = osp.dirname(osp.abspath(__file__))
+
migrschema = None
def tearDownModule(*args):
global migrschema
del migrschema
if hasattr(MigrationCommandsTC, 'origschema'):
del MigrationCommandsTC.origschema
+ if hasattr(MigrationCommandsComputedTC, 'origschema'):
+ del MigrationCommandsComputedTC.origschema
-class MigrationCommandsTC(CubicWebTC):
+class MigrationTC(CubicWebTC):
configcls = cubicweb.devtools.TestServerConfiguration
tags = CubicWebTC.tags | Tags(('server', 'migration', 'migractions'))
def _init_repo(self):
- super(MigrationCommandsTC, self)._init_repo()
+ super(MigrationTC, self)._init_repo()
# we have to read schema from the database to get eid for schema entities
self.repo.set_schema(self.repo.deserialize_schema(), resetvreg=False)
# hack to read the schema from data/migrschema
config = self.config
- config.appid = join('data', 'migratedapp')
- config._apphome = self.datapath('migratedapp')
+ config.appid = osp.join(self.appid, 'migratedapp')
+ config._apphome = osp.join(HERE, config.appid)
global migrschema
migrschema = config.load_schema()
- config.appid = 'data'
- config._apphome = self.datadir
- assert 'Folder' in migrschema
+ config.appid = self.appid
+ config._apphome = osp.join(HERE, self.appid)
def setUp(self):
CubicWebTC.setUp(self)
@@ -73,6 +77,13 @@
repo=self.repo, cnx=cnx,
interactive=False)
+
+class MigrationCommandsTC(MigrationTC):
+
+ def _init_repo(self):
+ super(MigrationCommandsTC, self)._init_repo()
+ assert 'Folder' in migrschema
+
def test_add_attribute_bool(self):
with self.mh() as (cnx, mh):
self.assertNotIn('yesno', self.schema)
@@ -667,5 +678,31 @@
"and name='same_as_relation'")
self.assertTrue(same_as_sql)
+
+class MigrationCommandsComputedTC(MigrationTC):
+ """ Unit tests for computed relations and attributes
+ """
+ appid = 'datacomputed'
+
+ def test_computed_relation_add_relation_definition(self):
+ self.assertNotIn('works_for', self.schema)
+ with self.mh() as (cnx, mh):
+ with self.assertRaises(ExecutionError) as exc:
+ mh.cmd_add_relation_definition('Employee', 'works_for',
+ 'Company')
+ self.assertEqual(str(exc.exception),
+ 'Cannot add a relation definition for a computed '
+ 'relation (works_for)')
+
+ def test_computed_relation_drop_relation_definition(self):
+ self.assertIn('notes', self.schema)
+ with self.mh() as (cnx, mh):
+ with self.assertRaises(ExecutionError) as exc:
+ mh.cmd_drop_relation_definition('Company', 'notes', 'Note')
+ self.assertEqual(str(exc.exception),
+ 'Cannot drop a relation definition for a computed '
+ 'relation (notes)')
+
+
if __name__ == '__main__':
unittest_main()