# HG changeset patch # User Laura Médioni # Date 1409204971 -7200 # Node ID cef58bd36f7bf6e7adfd186ac03492060578d24f # Parent 6359f3121f3fe7f2c5b8ba28cc368cd8c029f6e6 [CWEP002 migration] properly raise exception on (add|drop)_relation_definition for computed relation Related to #3546717 diff -r 6359f3121f3f -r cef58bd36f7b server/migractions.py --- 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' diff -r 6359f3121f3f -r cef58bd36f7b server/test/datacomputed/migratedapp/schema.py --- /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 . + +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' + diff -r 6359f3121f3f -r cef58bd36f7b server/test/datacomputed/schema.py --- /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 . + +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' diff -r 6359f3121f3f -r cef58bd36f7b server/test/unittest_migractions.py --- 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()