# HG changeset patch # User Julien Cristau # Date 1435824947 -7200 # Node ID 49a5c38de1dec1e2c5e1b433527748c558bcf48c # Parent d88fb5ccc8e699ed04d5ec93b8a61544867e44d4 [server/test] stop using email cube - make unittest_migractions use a separate datadir, and add a fake email cube there (we use it to test {add,drop}_cube, so need something that looks like a cube) - for the other test modules, just copy what we need from cubicweb-email's schema to our test schema diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/bootstrap_cubes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/bootstrap_cubes Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,1 @@ +card,comment,tag,basket,file,localperms,fakeemail diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/cubes/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/cubes/__init__.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/cubes/fakeemail/__init__.py diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/cubes/fakeemail/__pkginfo__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/cubes/fakeemail/__pkginfo__.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,53 @@ +# pylint: disable-msg=W0622 +"""cubicweb-fakeemail packaging information""" + +modname = 'fakeemail' +distname = "cubicweb-%s" % modname + +numversion = (1, 10, 0) +version = '.'.join(str(num) for num in numversion) + +license = 'LGPL' +author = "Logilab" +author_email = "contact@logilab.fr" +web = 'http://www.cubicweb.org/project/%s' % distname +description = "email component for the CubicWeb framework" +classifiers = [ + 'Environment :: Web Environment', + 'Framework :: CubicWeb', + 'Programming Language :: Python', + 'Programming Language :: JavaScript', +] + +# used packages +__depends__ = {'cubicweb': '>= 3.19.0', + 'cubicweb-file': '>= 1.9.0', + 'logilab-common': '>= 0.58.3', + } +__recommends__ = {'cubicweb-comment': None} + + +# packaging ### + +from os import listdir as _listdir +from os.path import join, isdir +from glob import glob + +THIS_CUBE_DIR = join('share', 'cubicweb', 'cubes', modname) + +def listdir(dirpath): + return [join(dirpath, fname) for fname in _listdir(dirpath) + if fname[0] != '.' and not fname.endswith('.pyc') + and not fname.endswith('~') + and not isdir(join(dirpath, fname))] + +data_files = [ + # common files + [THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']], + ] +# check for possible extended cube layout +for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration', 'wdoc'): + if isdir(dirname): + data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)]) +# Note: here, you'll need to add subdirectories if you want +# them to be included in the debian package diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/cubes/fakeemail/schema.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/cubes/fakeemail/schema.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,88 @@ +"""entity/relation schemas to store email in an cubicweb instance + +:organization: Logilab +:copyright: 2006-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" +_ = unicode + +# pylint: disable-msg=E0611,F0401 +from yams.buildobjs import (SubjectRelation, RelationType, EntityType, + String, Datetime, Int, RelationDefinition) +from yams.reader import context + +from cubicweb.schema import ERQLExpression + + +class Email(EntityType): + """electronic mail""" + subject = String(fulltextindexed=True) + date = Datetime(description=_('UTC time on which the mail was sent')) + messageid = String(required=True, indexed=True) + headers = String(description=_('raw headers')) + + sender = SubjectRelation('EmailAddress', cardinality='?*') + # an email with only Bcc is acceptable, don't require any recipients + recipients = SubjectRelation('EmailAddress') + cc = SubjectRelation('EmailAddress') + + parts = SubjectRelation('EmailPart', cardinality='*1', composite='subject') + attachment = SubjectRelation('File') + + reply_to = SubjectRelation('Email', cardinality='?*') + cites = SubjectRelation('Email') + in_thread = SubjectRelation('EmailThread', cardinality='?*') + + +class EmailPart(EntityType): + """an email attachment""" + __permissions__ = { + 'read': ('managers', 'users', 'guests',), # XXX if E parts X, U has_read_permission E + 'add': ('managers', ERQLExpression('E parts X, U has_update_permission E'),), + 'delete': ('managers', ERQLExpression('E parts X, U has_update_permission E')), + 'update': ('managers', 'owners',), + } + + content = String(fulltextindexed=True) + content_format = String(required=True, maxsize=50) + ordernum = Int(required=True) + alternative = SubjectRelation('EmailPart', symmetric=True) + + +class EmailThread(EntityType): + """discussion thread""" + title = String(required=True, indexed=True, fulltextindexed=True) + see_also = SubjectRelation('EmailThread') + forked_from = SubjectRelation('EmailThread', cardinality='?*') + +class parts(RelationType): + """ """ + fulltext_container = 'subject' + +class sender(RelationType): + """ """ + inlined = True + +class in_thread(RelationType): + """ """ + inlined = True + +class reply_to(RelationType): + """ """ + inlined = True + +class generated_by(RelationType): + """mark an entity as generated from an email""" + cardinality = '?*' + subject = ('TrInfo',) + object = 'Email' + +# if comment is installed +if 'Comment' in context.defined: + class comment_generated_by(RelationDefinition): + subject = 'Comment' + name = 'generated_by' + object = 'Email' + + diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/migratedapp/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/migratedapp/__init__.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,17 @@ +# copyright 2003-2010 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 . diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/migratedapp/bootstrap_cubes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/migratedapp/bootstrap_cubes Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,1 @@ +card,comment,tag,basket,fakeemail,file diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/migratedapp/schema.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/migratedapp/schema.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,206 @@ +# copyright 2003-2013 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 . +"""cw.server.migraction test""" +import datetime as dt +from yams.buildobjs import (EntityType, RelationType, RelationDefinition, + SubjectRelation, Bytes, + RichString, String, Int, Boolean, Datetime, Date) +from yams.constraints import SizeConstraint, UniqueConstraint +from cubicweb.schema import (WorkflowableEntityType, RQLConstraint, + RQLVocabularyConstraint, + ERQLExpression, RRQLExpression) + +class Affaire(EntityType): + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')), + 'update': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), + 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), + } + + ref = String(fulltextindexed=True, indexed=True, + constraints=[SizeConstraint(16)]) + sujet = String(fulltextindexed=True, + constraints=[SizeConstraint(256)]) + concerne = SubjectRelation('Societe') + opt_attr = Bytes() + +class Societe(WorkflowableEntityType): + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'update': ('managers', 'owners'), + 'delete': ('managers', 'owners'), + 'add': ('managers', 'users',) + } + nom = String(maxsize=64, fulltextindexed=True) + web = String(maxsize=128) + tel = Int() + fax = Int() + rncs = String(maxsize=128) + ad1 = String(maxsize=128) + ad2 = String(maxsize=128) + ad3 = String(maxsize=128) + cp = String(maxsize=12) + ville= String(maxsize=32) + +# Division and SubDivision are gone + +# New +class Para(EntityType): + para = String(maxsize=512) + newattr = String() + newinlined = SubjectRelation('Affaire', cardinality='?*', inlined=True) + newnotinlined = SubjectRelation('Affaire', cardinality='?*') + +class Note(Para): + __specializes_schema__ = True + + __permissions__ = {'read': ('managers', 'users', 'guests',), + 'update': ('managers', 'owners',), + 'delete': ('managers', ), + 'add': ('managers', + ERQLExpression('X ecrit_part PE, U in_group G, ' + 'PE require_permission P, P name "add_note", ' + 'P require_group G'),)} + + whatever = Int(default=0) # keep it before `date` for unittest_migraction.test_add_attribute_int + yesno = Boolean(default=False) + date = Datetime() + type = String(maxsize=1) + unique_id = String(maxsize=1, required=True, unique=True) + mydate = Date(default='TODAY') + oldstyledefaultdate = Date(default='2013/01/01') + newstyledefaultdate = Date(default=dt.date(2013, 1, 1)) + shortpara = String(maxsize=64, default='hop') + ecrit_par = SubjectRelation('Personne', constraints=[RQLConstraint('S concerne A, O concerne A')]) + attachment = SubjectRelation('File') + + +class Frozable(EntityType): + __permissions__ = { + 'read': ('managers', 'users'), + 'add': ('managers', 'users'), + 'update': ('managers', ERQLExpression('X frozen False'),), + 'delete': ('managers', ERQLExpression('X frozen False'),) + } + name = String() + frozen = Boolean(default=False, + __permissions__ = { + 'read': ('managers', 'users'), + 'add': ('managers', 'users'), + 'update': ('managers', 'owners') + }) + + +class Personne(EntityType): + __unique_together__ = [('nom', 'prenom', 'datenaiss')] + nom = String(fulltextindexed=True, required=True, maxsize=64) + prenom = String(fulltextindexed=True, maxsize=64) + civility = String(maxsize=1, default='M', fulltextindexed=True) + promo = String(vocabulary=('bon','pasbon')) + titre = String(fulltextindexed=True, maxsize=128) + adel = String(maxsize=128) + ass = String(maxsize=128) + web = String(maxsize=128) + tel = Int() + fax = Int() + datenaiss = Datetime() + test = Boolean() + + travaille = SubjectRelation('Societe') + concerne = SubjectRelation('Affaire') + concerne2 = SubjectRelation(('Affaire', 'Note'), cardinality='1*') + connait = SubjectRelation('Personne', symmetric=True) + +class concerne(RelationType): + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'add': ('managers', RRQLExpression('U has_update_permission S')), + 'delete': ('managers', RRQLExpression('O owned_by U')), + } + +# `Old` entity type is gonce +# `comments` is gone +# `fiche` is gone +# `multisource_*` rdefs are gone +# `see_also_*` rdefs are gone + +class evaluee(RelationDefinition): + subject = ('Personne', 'CWUser', 'Societe') + object = ('Note') + constraints = [RQLVocabularyConstraint('S owned_by U')] + +class ecrit_par(RelationType): + __permissions__ = {'read': ('managers', 'users', 'guests',), + 'delete': ('managers', ), + 'add': ('managers', + RRQLExpression('O require_permission P, P name "add_note", ' + 'U in_group G, P require_group G'),) + } + inlined = True + cardinality = '?*' + +# `copain` rdef is gone +# `tags` rdef is gone +# `filed_under` rdef is gone +# `require_permission` rdef is gone +# `require_state` rdef is gone +# `personne_composite` rdef is gone +# `personne_inlined` rdef is gone +# `login_user` rdef is gone +# `ambiguous_inlined` rdef is gone + +class Folder(EntityType): + """folders are used to classify entities. They may be defined as a tree. + """ + name = String(required=True, indexed=True, internationalizable=True, + maxsize=64) + description = RichString(fulltextindexed=True) + filed_under = SubjectRelation('Folder', description=_('parent folder')) + + +# New +class Text(Para): + __specializes_schema__ = True + summary = String(maxsize=512) + + +# New +class Folder2(EntityType): + """folders are used to classify entities. They may be defined as a tree. + When you include the Folder entity, all application specific entities + may then be classified using the "filed_under" relation. + """ + name = String(required=True, indexed=True, internationalizable=True, + constraints=[UniqueConstraint(), SizeConstraint(64)]) + description = RichString(fulltextindexed=True) + +# New +class filed_under2(RelationDefinition): + subject ='*' + object = 'Folder2' + + +# New +class New(EntityType): + new_name = String() + +# New +class same_as(RelationDefinition): + subject = ('Societe',) + object = 'ExternalUri' diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data-migractions/schema.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/test/data-migractions/schema.py Thu Jul 02 10:15:47 2015 +0200 @@ -0,0 +1,288 @@ +# copyright 2003-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, RelationType, RelationDefinition, ComputedRelation, + SubjectRelation, RichString, String, Int, Float, + Boolean, Datetime, TZDatetime, Bytes) +from yams.constraints import SizeConstraint +from cubicweb.schema import (WorkflowableEntityType, + RQLConstraint, RQLUniqueConstraint, + RQLVocabularyConstraint, + ERQLExpression, RRQLExpression) + +class Affaire(WorkflowableEntityType): + __permissions__ = { + 'read': ('managers', + ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')), + 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')), + 'update': ('managers', 'owners', ERQLExpression('X in_state S, S name in ("pitetre", "en cours")')), + 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), + } + + ref = String(fulltextindexed=True, indexed=True, + constraints=[SizeConstraint(16)]) + sujet = String(fulltextindexed=True, + constraints=[SizeConstraint(256)]) + descr = RichString(fulltextindexed=True, + description=_('more detailed description')) + + duration = Int() + invoiced = Float() + opt_attr = Bytes() + + depends_on = SubjectRelation('Affaire') + require_permission = SubjectRelation('CWPermission') + concerne = SubjectRelation(('Societe', 'Note')) + todo_by = SubjectRelation('Personne', cardinality='?*') + documented_by = SubjectRelation('Card') + + +class Societe(EntityType): + __unique_together__ = [('nom', 'type', 'cp')] + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')), + 'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')), + 'add': ('managers', 'users',) + } + + nom = String(maxsize=64, fulltextindexed=True) + web = String(maxsize=128) + type = String(maxsize=128) # attribute in common with Note + tel = Int() + fax = Int() + rncs = String(maxsize=128) + ad1 = String(maxsize=128) + ad2 = String(maxsize=128) + ad3 = String(maxsize=128) + cp = String(maxsize=12) + ville= String(maxsize=32) + + +class Division(Societe): + __specializes_schema__ = True + +class SubDivision(Division): + __specializes_schema__ = True + +class travaille_subdivision(RelationDefinition): + subject = 'Personne' + object = 'SubDivision' + +from cubicweb.schemas.base import CWUser +CWUser.get_relations('login').next().fulltextindexed = True + +class Note(WorkflowableEntityType): + date = String(maxsize=10) + type = String(vocabulary=[u'todo', u'a', u'b', u'T', u'lalala']) + para = String(maxsize=512, + __permissions__ = { + 'add': ('managers', ERQLExpression('X in_state S, S name "todo"')), + 'read': ('managers', 'users', 'guests'), + 'update': ('managers', ERQLExpression('X in_state S, S name "todo"')), + }) + something = String(maxsize=1, + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'add': (ERQLExpression('NOT X para NULL'),), + 'update': ('managers', 'owners') + }) + migrated_from = SubjectRelation('Note') + attachment = SubjectRelation('File') + inline1 = SubjectRelation('Affaire', inlined=True, cardinality='?*', + constraints=[RQLUniqueConstraint('S type T, S inline1 A1, A1 todo_by C, ' + 'Y type T, Y inline1 A2, A2 todo_by C', + 'S,Y')]) + todo_by = SubjectRelation('CWUser') + + +class Frozable(EntityType): + __permissions__ = { + 'read': ('managers', 'users'), + 'add': ('managers', 'users'), + 'update': ('managers', ERQLExpression('X frozen False'),), + 'delete': ('managers', ERQLExpression('X frozen False'),) + } + name = String() + frozen = Boolean(default=False, + __permissions__ = { + 'read': ('managers', 'users'), + 'add': ('managers', 'users'), + 'update': ('managers', 'owners') + }) + + +class Personne(EntityType): + __unique_together__ = [('nom', 'prenom', 'inline2')] + nom = String(fulltextindexed=True, required=True, maxsize=64) + prenom = String(fulltextindexed=True, maxsize=64) + sexe = String(maxsize=1, default='M', fulltextindexed=True) + promo = String(vocabulary=('bon','pasbon')) + titre = String(fulltextindexed=True, maxsize=128) + adel = String(maxsize=128) + ass = String(maxsize=128) + web = String(maxsize=128) + tel = Int() + fax = Int() + datenaiss = Datetime() + tzdatenaiss = TZDatetime() + test = Boolean(__permissions__={ + 'read': ('managers', 'users', 'guests'), + 'add': ('managers',), + 'update': ('managers',), + }) + description = String() + firstname = String(fulltextindexed=True, maxsize=64) + + concerne = SubjectRelation('Affaire') + connait = SubjectRelation('Personne') + inline2 = SubjectRelation('Affaire', inlined=True, cardinality='?*') + + +class Old(EntityType): + name = String(__permissions__ = { + 'read' : ('managers', 'users', 'guests'), + 'add' : ('managers', 'users', 'guests'), + 'update' : () + }) + + +class connait(RelationType): + symmetric = True + +class concerne(RelationType): + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'add': ('managers', RRQLExpression('U has_update_permission S')), + 'delete': ('managers', RRQLExpression('O owned_by U')), + } + +class travaille(RelationDefinition): + __permissions__ = { + 'read': ('managers', 'users', 'guests'), + 'add': ('managers', RRQLExpression('U has_update_permission S')), + 'delete': ('managers', RRQLExpression('O owned_by U')), + } + subject = 'Personne' + object = 'Societe' + constraints = [RQLVocabularyConstraint('S owned_by U'), + RQLVocabularyConstraint('S created_by U')] + +class comments(RelationDefinition): + subject = 'Comment' + object = 'Personne' + +class fiche(RelationDefinition): + inlined = True + subject = 'Personne' + object = 'Card' + cardinality = '??' + +class multisource_inlined_rel(RelationDefinition): + inlined = True + cardinality = '?*' + subject = ('Card', 'Note') + object = ('Affaire', 'Note') + + +class see_also_1(RelationDefinition): + name = 'see_also' + subject = object = 'Folder' + +class see_also_2(RelationDefinition): + name = 'see_also' + subject = ('Bookmark', 'Note') + object = ('Bookmark', 'Note') + +class evaluee(RelationDefinition): + subject = ('Personne', 'CWUser', 'Societe') + object = ('Note') + constraints = [ + RQLVocabularyConstraint('S created_by U'), + RQLVocabularyConstraint('S owned_by U'), + ] + +class ecrit_par(RelationType): + inlined = True + +class ecrit_par_1(RelationDefinition): + name = 'ecrit_par' + subject = 'Note' + object ='Personne' + cardinality = '?*' + +class ecrit_par_2(RelationDefinition): + name = 'ecrit_par' + subject = 'Note' + object ='CWUser' + cardinality='?*' + + +class copain(RelationDefinition): + subject = object = 'CWUser' + +class tags(RelationDefinition): + subject = 'Tag' + object = ('CWUser', 'CWGroup', 'State', 'Note', 'Card', 'Affaire') + +class Folder(EntityType): + """folders are used to classify entities. They may be defined as a tree. + """ + name = String(required=True, indexed=True, internationalizable=True, + maxsize=64) + description = RichString(fulltextindexed=True) + filed_under = SubjectRelation('Folder', description=_('parent folder')) + +class filed_under(RelationDefinition): + subject = ('Note', 'Affaire') + object = 'Folder' + +class require_permission(RelationDefinition): + subject = ('Card', 'Note', 'Personne') + object = 'CWPermission' + +class require_state(RelationDefinition): + subject = 'CWPermission' + object = 'State' + +class personne_composite(RelationDefinition): + subject='Personne' + object='Personne' + composite='subject' + +class personne_inlined(RelationDefinition): + subject='Personne' + object='Personne' + cardinality='?*' + inlined=True + + +class login_user(RelationDefinition): + subject = 'Personne' + object = 'CWUser' + cardinality = '??' + +class ambiguous_inlined(RelationDefinition): + subject = ('Affaire', 'Note') + object = 'CWUser' + inlined = True + cardinality = '?*' + + +class user_login(ComputedRelation): + rule = 'O login_user S' diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data/bootstrap_cubes --- a/server/test/data/bootstrap_cubes Thu Jul 02 16:13:05 2015 +0200 +++ b/server/test/data/bootstrap_cubes Thu Jul 02 10:15:47 2015 +0200 @@ -1,1 +1,1 @@ -card,comment,tag,basket,email,file,localperms +card,comment,tag,basket,file,localperms diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data/migratedapp/__init__.py --- a/server/test/data/migratedapp/__init__.py Thu Jul 02 16:13:05 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -# copyright 2003-2010 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 . diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data/migratedapp/bootstrap_cubes --- a/server/test/data/migratedapp/bootstrap_cubes Thu Jul 02 16:13:05 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -card,comment,tag,basket,email,file diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data/migratedapp/schema.py --- a/server/test/data/migratedapp/schema.py Thu Jul 02 16:13:05 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -# copyright 2003-2013 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 . -"""cw.server.migraction test""" -import datetime as dt -from yams.buildobjs import (EntityType, RelationType, RelationDefinition, - SubjectRelation, Bytes, - RichString, String, Int, Boolean, Datetime, Date) -from yams.constraints import SizeConstraint, UniqueConstraint -from cubicweb.schema import (WorkflowableEntityType, RQLConstraint, - RQLVocabularyConstraint, - ERQLExpression, RRQLExpression) - -class Affaire(EntityType): - __permissions__ = { - 'read': ('managers', 'users', 'guests'), - 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')), - 'update': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), - 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')), - } - - ref = String(fulltextindexed=True, indexed=True, - constraints=[SizeConstraint(16)]) - sujet = String(fulltextindexed=True, - constraints=[SizeConstraint(256)]) - concerne = SubjectRelation('Societe') - opt_attr = Bytes() - -class Societe(WorkflowableEntityType): - __permissions__ = { - 'read': ('managers', 'users', 'guests'), - 'update': ('managers', 'owners'), - 'delete': ('managers', 'owners'), - 'add': ('managers', 'users',) - } - nom = String(maxsize=64, fulltextindexed=True) - web = String(maxsize=128) - tel = Int() - fax = Int() - rncs = String(maxsize=128) - ad1 = String(maxsize=128) - ad2 = String(maxsize=128) - ad3 = String(maxsize=128) - cp = String(maxsize=12) - ville= String(maxsize=32) - -# Division and SubDivision are gone - -# New -class Para(EntityType): - para = String(maxsize=512) - newattr = String() - newinlined = SubjectRelation('Affaire', cardinality='?*', inlined=True) - newnotinlined = SubjectRelation('Affaire', cardinality='?*') - -class Note(Para): - __specializes_schema__ = True - - __permissions__ = {'read': ('managers', 'users', 'guests',), - 'update': ('managers', 'owners',), - 'delete': ('managers', ), - 'add': ('managers', - ERQLExpression('X ecrit_part PE, U in_group G, ' - 'PE require_permission P, P name "add_note", ' - 'P require_group G'),)} - - whatever = Int(default=0) # keep it before `date` for unittest_migraction.test_add_attribute_int - yesno = Boolean(default=False) - date = Datetime() - type = String(maxsize=1) - unique_id = String(maxsize=1, required=True, unique=True) - mydate = Date(default='TODAY') - oldstyledefaultdate = Date(default='2013/01/01') - newstyledefaultdate = Date(default=dt.date(2013, 1, 1)) - shortpara = String(maxsize=64, default='hop') - ecrit_par = SubjectRelation('Personne', constraints=[RQLConstraint('S concerne A, O concerne A')]) - attachment = SubjectRelation('File') - - -class Frozable(EntityType): - __permissions__ = { - 'read': ('managers', 'users'), - 'add': ('managers', 'users'), - 'update': ('managers', ERQLExpression('X frozen False'),), - 'delete': ('managers', ERQLExpression('X frozen False'),) - } - name = String() - frozen = Boolean(default=False, - __permissions__ = { - 'read': ('managers', 'users'), - 'add': ('managers', 'users'), - 'update': ('managers', 'owners') - }) - - -class Personne(EntityType): - __unique_together__ = [('nom', 'prenom', 'datenaiss')] - nom = String(fulltextindexed=True, required=True, maxsize=64) - prenom = String(fulltextindexed=True, maxsize=64) - civility = String(maxsize=1, default='M', fulltextindexed=True) - promo = String(vocabulary=('bon','pasbon')) - titre = String(fulltextindexed=True, maxsize=128) - adel = String(maxsize=128) - ass = String(maxsize=128) - web = String(maxsize=128) - tel = Int() - fax = Int() - datenaiss = Datetime() - test = Boolean() - - travaille = SubjectRelation('Societe') - concerne = SubjectRelation('Affaire') - concerne2 = SubjectRelation(('Affaire', 'Note'), cardinality='1*') - connait = SubjectRelation('Personne', symmetric=True) - -class concerne(RelationType): - __permissions__ = { - 'read': ('managers', 'users', 'guests'), - 'add': ('managers', RRQLExpression('U has_update_permission S')), - 'delete': ('managers', RRQLExpression('O owned_by U')), - } - -# `Old` entity type is gonce -# `comments` is gone -# `fiche` is gone -# `multisource_*` rdefs are gone -# `see_also_*` rdefs are gone - -class evaluee(RelationDefinition): - subject = ('Personne', 'CWUser', 'Societe') - object = ('Note') - constraints = [RQLVocabularyConstraint('S owned_by U')] - -class ecrit_par(RelationType): - __permissions__ = {'read': ('managers', 'users', 'guests',), - 'delete': ('managers', ), - 'add': ('managers', - RRQLExpression('O require_permission P, P name "add_note", ' - 'U in_group G, P require_group G'),) - } - inlined = True - cardinality = '?*' - -# `copain` rdef is gone -# `tags` rdef is gone -# `filed_under` rdef is gone -# `require_permission` rdef is gone -# `require_state` rdef is gone -# `personne_composite` rdef is gone -# `personne_inlined` rdef is gone -# `login_user` rdef is gone -# `ambiguous_inlined` rdef is gone - -class Folder(EntityType): - """folders are used to classify entities. They may be defined as a tree. - """ - name = String(required=True, indexed=True, internationalizable=True, - maxsize=64) - description = RichString(fulltextindexed=True) - filed_under = SubjectRelation('Folder', description=_('parent folder')) - - -# New -class Text(Para): - __specializes_schema__ = True - summary = String(maxsize=512) - - -# New -class Folder2(EntityType): - """folders are used to classify entities. They may be defined as a tree. - When you include the Folder entity, all application specific entities - may then be classified using the "filed_under" relation. - """ - name = String(required=True, indexed=True, internationalizable=True, - constraints=[UniqueConstraint(), SizeConstraint(64)]) - description = RichString(fulltextindexed=True) - -# New -class filed_under2(RelationDefinition): - subject ='*' - object = 'Folder2' - - -# New -class New(EntityType): - new_name = String() - -# New -class same_as(RelationDefinition): - subject = ('Societe',) - object = 'ExternalUri' diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/data/schema.py --- a/server/test/data/schema.py Thu Jul 02 16:13:05 2015 +0200 +++ b/server/test/data/schema.py Thu Jul 02 10:15:47 2015 +0200 @@ -162,6 +162,22 @@ }) +class Email(EntityType): + subject = String(fulltextindexed=True) + messageid = String(required=True, indexed=True, unique=True) + sender = SubjectRelation('EmailAddress', cardinality='?*') + recipients = SubjectRelation('EmailAddress') + attachment = SubjectRelation('File') + + +class EmailPart(EntityType): + pass + + +class EmailThread(EntityType): + see_also = SubjectRelation('EmailThread') + + class connait(RelationType): symmetric = True diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/unittest_migractions.py --- a/server/test/unittest_migractions.py Thu Jul 02 16:13:05 2015 +0200 +++ b/server/test/unittest_migractions.py Thu Jul 02 10:15:47 2015 +0200 @@ -18,7 +18,7 @@ """unit tests for module cubicweb.server.migractions""" from datetime import date -import os.path as osp +import os, os.path as osp from contextlib import contextmanager from logilab.common.testlib import unittest_main, Tags, tag @@ -54,10 +54,13 @@ class MigrationConfig(cubicweb.devtools.TestServerConfiguration): default_sources = cubicweb.devtools.DEFAULT_PSQL_SOURCES + CUBES_PATH = [osp.join(HERE, 'data-migractions', 'cubes')] class MigrationTC(CubicWebTC): + appid = 'data-migractions' + configcls = MigrationConfig tags = CubicWebTC.tags | Tags(('server', 'migration', 'migractions')) @@ -76,10 +79,11 @@ config._apphome = osp.join(HERE, self.appid) def setUp(self): - CubicWebTC.setUp(self) + self.configcls.cls_adjust_sys_path() + super(MigrationTC, self).setUp() def tearDown(self): - CubicWebTC.tearDown(self) + super(MigrationTC, self).tearDown() self.repo.vreg['etypes'].clear_caches() @contextmanager @@ -577,15 +581,15 @@ ('Bookmark', 'Bookmark'), ('Bookmark', 'Note'), ('Note', 'Note'), ('Note', 'Bookmark')])) try: - mh.cmd_drop_cube('email', removedeps=True) + mh.cmd_drop_cube('fakeemail', removedeps=True) # file was there because it's an email dependancy, should have been removed - self.assertNotIn('email', self.config.cubes()) - self.assertNotIn(self.config.cube_dir('email'), self.config.cubes_path()) + self.assertNotIn('fakeemail', self.config.cubes()) + self.assertNotIn(self.config.cube_dir('fakeemail'), self.config.cubes_path()) self.assertNotIn('file', self.config.cubes()) self.assertNotIn(self.config.cube_dir('file'), self.config.cubes_path()) for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'sender', 'in_thread', 'reply_to', 'data_format'): - self.assertFalse(ertype in schema, ertype) + self.assertNotIn(ertype, schema) self.assertEqual(sorted(schema['see_also'].rdefs.iterkeys()), sorted([('Folder', 'Folder'), ('Bookmark', 'Bookmark'), @@ -594,17 +598,17 @@ ('Note', 'Bookmark')])) self.assertEqual(sorted(schema['see_also'].subjects()), ['Bookmark', 'Folder', 'Note']) self.assertEqual(sorted(schema['see_also'].objects()), ['Bookmark', 'Folder', 'Note']) - self.assertEqual(cnx.execute('Any X WHERE X pkey "system.version.email"').rowcount, 0) + self.assertEqual(cnx.execute('Any X WHERE X pkey "system.version.fakeemail"').rowcount, 0) self.assertEqual(cnx.execute('Any X WHERE X pkey "system.version.file"').rowcount, 0) finally: - mh.cmd_add_cube('email') - self.assertIn('email', self.config.cubes()) - self.assertIn(self.config.cube_dir('email'), self.config.cubes_path()) + mh.cmd_add_cube('fakeemail') + self.assertIn('fakeemail', self.config.cubes()) + self.assertIn(self.config.cube_dir('fakeemail'), self.config.cubes_path()) self.assertIn('file', self.config.cubes()) self.assertIn(self.config.cube_dir('file'), self.config.cubes_path()) for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'sender', 'in_thread', 'reply_to', 'data_format'): - self.assertTrue(ertype in schema, ertype) + self.assertIn(ertype, schema) self.assertEqual(sorted(schema['see_also'].rdefs.iterkeys()), sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'), ('Bookmark', 'Bookmark'), @@ -613,9 +617,9 @@ ('Note', 'Bookmark')])) self.assertEqual(sorted(schema['see_also'].subjects()), ['Bookmark', 'EmailThread', 'Folder', 'Note']) self.assertEqual(sorted(schema['see_also'].objects()), ['Bookmark', 'EmailThread', 'Folder', 'Note']) - from cubes.email.__pkginfo__ import version as email_version + from cubes.fakeemail.__pkginfo__ import version as email_version from cubes.file.__pkginfo__ import version as file_version - self.assertEqual(cnx.execute('Any V WHERE X value V, X pkey "system.version.email"')[0][0], + self.assertEqual(cnx.execute('Any V WHERE X value V, X pkey "system.version.fakeemail"')[0][0], email_version) self.assertEqual(cnx.execute('Any V WHERE X value V, X pkey "system.version.file"')[0][0], file_version) @@ -633,16 +637,16 @@ cubes = set(self.config.cubes()) schema = self.repo.schema try: - mh.cmd_drop_cube('email') - cubes.remove('email') - self.assertNotIn('email', self.config.cubes()) + mh.cmd_drop_cube('fakeemail') + cubes.remove('fakeemail') + self.assertNotIn('fakeemail', self.config.cubes()) self.assertIn('file', self.config.cubes()) for ertype in ('Email', 'EmailThread', 'EmailPart', 'sender', 'in_thread', 'reply_to'): - self.assertFalse(ertype in schema, ertype) + self.assertNotIn(ertype, schema) finally: - mh.cmd_add_cube('email') - self.assertIn('email', self.config.cubes()) + mh.cmd_add_cube('fakeemail') + self.assertIn('fakeemail', self.config.cubes()) # trick: overwrite self.maxeid to avoid deletion of just reintroduced # types (and their associated tables!) self.maxeid = cnx.execute('Any MAX(X)')[0][0] # XXXXXXX KILL KENNY diff -r d88fb5ccc8e6 -r 49a5c38de1de server/test/unittest_repository.py --- a/server/test/unittest_repository.py Thu Jul 02 16:13:05 2015 +0200 +++ b/server/test/unittest_repository.py Thu Jul 02 10:15:47 2015 +0200 @@ -500,7 +500,6 @@ u'system.version.card', u'system.version.comment', u'system.version.cubicweb', - u'system.version.email', u'system.version.file', u'system.version.localperms', u'system.version.tag'])