I am trying to test my Dexterity content using plone.app.testing and I
encountered a problem with local roles (borg.localrole). The content type
works (i.e. I can add, edit, view etc.) and the local roles work on the
content type but my test fails with the following traceback:
Running ins.engagement.tests.setupintegration.ins.engagement:Integration
tests:
Set up plone.testing.zca.LayerCleanup in 0.000 seconds.
Set up plone.testing.z2.Startup in 0.781 seconds.
Set up plone.app.testing.layers.PloneFixture in 21.095 seconds.
Set up
ins.engagement.tests.setupintegration.InsEngagementd:\development\engagement\eggs\five.intid-0.4.2-py2.6.egg\five\intid\site.py:5:
DeprecationWarning:
ISite is deprecated. Moved to zope.location.interfaces. Importing from here
will stop working in Zope 3.6
from zope.app.component.interfaces import ISite
d:\development\engagement\eggs\five.intid-0.4.2-py2.6.egg\five\intid\intid.py:1:
DeprecationWarning: InitializeClass is deprecated. import from
App.class_init i
nstead
from Globals import InitializeClass
d:\development\engagement\eggs\zope.app.testing-3.7.3-py2.6.egg\zope\app\testing\functional.py:42:
DeprecationWarning: zope.testing.doctest is deprecated in fav
our of the Python standard library doctest module
from zope.testing import doctest
d:\development\engagement\eggs\zope.configuration-3.6.0-py2.6.egg\zope\configuration\fields.py:419:
UserWarning: You did not specify an i18n translation domain
for the 'description' field in
d:\development\engagement\src\ins.engagement\ins\engagement\configure.zcml
"'%s' field in %s" % (self.getName(), context.info.file )
d:\development\engagement\eggs\zope.configuration-3.6.0-py2.6.egg\zope\configuration\fields.py:419:
UserWarning: You did not specify an i18n translation domain
for the 'title' field in
d:\development\engagement\src\ins.engagement\ins\engagement\configure.zcml
"'%s' field in %s" % (self.getName(), context.info.file )
in 6.375 seconds.
Set up ins.engagement.tests.setupintegration.ins.engagement:Integration in
0.000 seconds.
Running:
1/1 (100.0%)
Error in test test_adding
(ins.engagement.tests.test_integration.IntegrationTestCase)
Traceback (most recent call last):
File
"d:\development\engagement\eggs\unittest2-0.5.1-py2.6.egg\unittest2\case.py",
line 340, in run
testMethod()
File
"d:\development\engagement\src\ins.engagement\ins\engagement\tests\test_integration.py",
line 18, in test_adding
f1.invokeFactory('ins.engagement.engagement', 'engagement1')
File
"d:\development\engagement\eggs\products.atcontenttypes-2.0.3-py2.6.egg\Products\ATContentTypes\lib\constraintypes.py",
line 257, in invokeFactory
RESPONSE=None, *args, **kw)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\PortalFolder.py",
line 295, in invokeFactory
return pt.constructContent(type_name, self, id, RESPONSE, *args, **kw)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\TypesTool.py",
line 835, in constructContent
ob = info.constructInstance(container, id, *args, **kw)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\TypesTool.py",
line 313, in constructInstance
return self._constructInstance(container, id, *args, **kw)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\TypesTool.py",
line 571, in _constructInstance
rval = container._setObject(id, obj)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\BTreeFolder2\BTreeFolder2.py",
line 450, in _setObject
notify(ObjectAddedEvent(ob, self, id))
File
"d:\development\engagement\eggs\zope.event-3.4.1-py2.6.egg\zope\event\__init__.py",
line 23, in notify
subscriber(event)
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\event.py",
line 26, in dispatch
for ignored in zope.component.subscribers(event, None):
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\_api.py",
line 138, in subscribers
return sitemanager.subscribers(objects, interface)
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\registry.py",
line 323, in subscribers
return self.adapters.subscribers(objects, provided)
File
"d:\development\engagement\eggs\zope.interface-3.5.3-py2.6-win32.egg\zope\interface\adapter.py",
line 575, in subscribers
subscription(*objects)
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\event.py",
line 33, in objectEventNotify
adapters = zope.component.subscribers((event.object, event), None)
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\_api.py",
line 138, in subscribers
return sitemanager.subscribers(objects, interface)
File
"d:\development\engagement\eggs\zope.component-3.7.1-py2.6.egg\zope\component\registry.py",
line 323, in subscribers
return self.adapters.subscribers(objects, provided)
File
"d:\development\engagement\eggs\zope.interface-3.5.3-py2.6-win32.egg\zope\interface\adapter.py",
line 575, in subscribers
subscription(*objects)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\CMFCatalogAware.py",
line 266, in handleContentishEvent
ob.indexObject()
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\CMFCatalogAware.py",
line 71, in indexObject
catalog.indexObject(self)
File
"d:\development\engagement\eggs\plone-4.0-py2.6.egg\Products\CMFPlone\CatalogTool.py",
line 272, in indexObject
self.reindexObject(object, idxs)
File
"d:\development\engagement\eggs\products.cmfcore-2.2.2-py2.6.egg\Products\CMFCore\CatalogTool.py",
line 304, in reindexObject
self.catalog_object(object, uid, idxs, update_metadata)
File
"d:\development\engagement\eggs\plone-4.0-py2.6.egg\Products\CMFPlone\CatalogTool.py",
line 287, in catalog_object
update_metadata, pghandler=pghandler)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\ZCatalog\ZCatalog.py",
line 529, in catalog_object
update_metadata=update_metadata)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\ZCatalog\Catalog.py",
line 360, in catalogObject
blah = x.index_object(index, object, threshold)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\PluginIndexes\common\UnIndex.py",
line 233, in index_object
res += self._index_object(documentId, obj, threshold, attr)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\PluginIndexes\KeywordIndex\KeywordIndex.py",
line 64, in _index_object
newKeywords = self._get_object_keywords(obj, attr)
File
"d:\development\engagement\eggs\zope2-2.12.10-py2.6-win32.egg\Products\PluginIndexes\KeywordIndex\KeywordIndex.py",
line 99, in _get_object_keywords
newKeywords = getattr(obj, attr, ())
File
"d:\development\engagement\eggs\plone.indexer-1.0-py2.6.egg\plone\indexer\wrapper.py",
line 59, in __getattr__
return indexer()
File
"d:\development\engagement\eggs\plone.indexer-1.0-py2.6.egg\plone\indexer\delegate.py",
line 16, in __call__
return self.callable(self.context)
File
"d:\development\engagement\eggs\plone-4.0-py2.6.egg\Products\CMFPlone\CatalogTool.py",
line 62, in allowedRolesAndUsers
localroles = acl_users._getAllLocalRoles(obj)
File
"d:\development\engagement\eggs\products.plonepas-4.0.1-py2.6.egg\Products\PlonePAS\pas.py",
line 383, in _getAllLocalRoles
newroles=lrmanager.getAllLocalRolesInContext(context)
File
"d:\development\engagement\eggs\borg.localrole-3.0.1-py2.6.egg\borg\localrole\workspace.py",
line 478, in getAllLocalRolesInContext
for principal, roles in iter_roles:
File
"d:\development\engagement\src\ins.engagement\ins\engagement\engagement.py",
line 181, in getAllRoles
for m in self.context.managers:
TypeError: 'NoneType' object is not iterable
Ran 1 tests with 0 failures and 1 errors in 0.281 seconds.
Running zope.testing.testrunner.layer.UnitTests tests:
Tear down ins.engagement.tests.setupintegration.ins.engagement:Integration
in 0.000 seconds.
Tear down ins.engagement.tests.setupintegration.InsEngagement in 0.015
seconds.
Tear down plone.app.testing.layers.PloneFixture in 0.532 seconds.
Tear down plone.testing.z2.Startup in 0.031 seconds.
Tear down plone.testing.zca.LayerCleanup in 0.000 seconds.
Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Running:
Ran 14 tests with 0 failures and 0 errors in 0.016 seconds.
Tearing down left over layers:
Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Total: 15 tests, 0 failures, 1 errors in 30.376 seconds.
The content type is:
from five import grok
from zope import schema
import datetime
from DateTime import DateTime
from Acquisition import aq_inner, aq_parent
from zope.schema.vocabulary import SimpleVocabulary
from zope.lifecycleevent.interfaces import IObjectCreatedEvent
from zope.lifecycleevent.interfaces import IObjectModifiedEvent
from zope.security import checkPermission
from plone.directives import form, dexterity
from plone.app.textfield import RichText
from z3c.relationfield.schema import RelationChoice
from plone.formwidget.contenttree import ObjPathSourceBinder
from Products.CMFCore.utils import getToolByName
from plone.formwidget.autocomplete import AutocompleteMultiFieldWidget
from borg.localrole.interfaces import ILocalRoleProvider
from zope.interface import invariant, Invalid
from plone.indexer import indexer
from ins.engagement.timeentry import ITimeentry
from ins.engagement.task import ITask
from ins.engagement import _
class StartBeforeEnd(Invalid):
__doc__ = _(u"The start or end date is invalid")
class IEngagement(form.Schema):
"""An Engagement. Engagements hold Source documents, Tasks and Time
entries.
"""
title = schema.TextLine(
title=_(u"Engagement Name"),
)
description = schema.Text(
title=_(u"Engagement summary"),
)
engagementtype = schema.Choice(
title=_(u"Type of Engagement"),
vocabulary=u"ins.engagement.engagementtypes",
required=True,
)
start = schema.Date(
title=_(u"Start date"),
required=False,
)
end = schema.Date(
title=_(u"End date"),
required=False,
)
periodend = schema.Date(
title=_(u"Period End"),
required=True,
)
periodendyear = schema.Choice(
title=_(u"Period End Year"),
vocabulary=u"ins.engagement.periodendyear",
required=True,
)
estimatedhours = schema.Decimal(
title=_(u"Estimated Hours"),
required=False,
)
# use an autocomplete selection widget instead of the default content
tree
form.widget(managers=AutocompleteMultiFieldWidget)
managers = schema.List(
title=_(u"Engagement Manager(s)"),
value_type=schema.Choice(
vocabulary=u"plone.principalsource.Users"),
required=False,
)
form.widget(members=AutocompleteMultiFieldWidget)
members = schema.List(
title=_(u"Staff Members"),
required=False,
default=[],
value_type=schema.Choice(
vocabulary=u"plone.principalsource.Users"),
)
# form.widget(clients=AutocompleteMultiFieldWidget)
clients = schema.List(
title=_(u"Client Users"),
required=False,
default=[],
value_type=schema.Choice(
vocabulary=u"ins.engagement.clients"),
)
form.primary('details')
details = RichText(
title=_(u"Engagement details"),
required=False
)
form.mode(server='hidden')
server = schema.TextLine(
title=_(u"Email Folder"),
required=False,
)
@invariant
def validateStartEnd(data):
if data.start is not None and data.end is not None:
if data.start > data.end:
raise StartBeforeEnd(_(u"The start date must be the same as
or before the end date."))
@form.default_value(field=IEngagement['start'])
def startDefaultValue(data):
# To get hold of the folder, do: context = data.context
return datetime.datetime.today()
@form.default_value(field=IEngagement['end'])
def endDefaultValue(data):
# To get hold of the folder, do: context = data.context
return datetime.datetime.today()
@form.default_value(field=IEngagement['periodendyear'])
def periodendyearDefaultValue(data):
# To get hold of the folder, do: context = data.context
today = datetime.date.today()
this_year = today.year
return str(this_year)
@grok.subscribe(IEngagement, IObjectCreatedEvent)
def setInitialServer(engagement, event):
if engagement.title:
engagement.server = engagement.title
@grok.subscribe(IEngagement, IObjectModifiedEvent)
def setServer(engagement, event):
if engagement.title != engagement.server:
engagement.server = engagement.title
engagement.reindexObject()
# Indexers
@indexer(IEngagement)
def startIndexer(obj):
if obj.start is None:
return None
return DateTime(obj.start.isoformat())
grok.global_adapter(startIndexer, name="start")
@indexer(IEngagement)
def endIndexer(obj):
if obj.end is None:
return None
return DateTime(obj.end.isoformat())
grok.global_adapter(endIndexer, name="end")
class LocalRoles(grok.Adapter):
"""Provide a local role manager for projects
"""
grok.provides(ILocalRoleProvider)
grok.context(IEngagement)
def __init__(self, context):
self.context = context
def getAllRoles(self):
for m in self.context.managers:
yield (m, ('Manager',))
for m in self.context.members:
yield (m, ('TeamMember',))
for m in self.context.clients:
yield (m, ('Client',))
def getRoles(self, principal_id):
roles = set()
if principal_id in self.context.managers:
roles.add('Manager')
if principal_id in self.context.members:
roles.add('TeamMember')
if principal_id in self.context.clients:
roles.add('Client')
return roles
class View(grok.View):
grok.context(IEngagement)
grok.require('zope2.View')
def clientname(self):
""" Get the name of the client this engagement is for
"""
context = aq_inner(self.context)
task = context.__parent__
clientname = task.title
return clientname
def reviewstate(self):
""" Return the state of the time entry
"""
context = aq_inner(self.context)
wtool = getToolByName(context, "portal_workflow")
wf_state = wtool.getInfoFor(context,'review_state',None)
return wf_state
def tasks(self):
"""Return a catalog search result of tasks to show
"""
context = aq_inner(self.context)
catalog = getToolByName(context, 'portal_catalog')
task_brains = catalog(object_provides=ITask.__identifier__,
path='/'.join(context.getPhysicalPath()),
sort_order='sortable_title')
return_values = []
for task in task_brains:
task_obj = task.getObject()
timeentry_brains =
catalog(object_provides=ITimeentry.__identifier__,
path='/'.join(task_obj.getPhysicalPath()),
sort_order='sortable_title')
work_hours = 0
for time_entry in timeentry_brains:
timeentry = time_entry.getObject()
work_hours = work_hours + timeentry.timeamount
return_values.append(dict(url=task.getURL(),
name=task.Title,
est_hours=task_obj.estimatedhours,
status=task.review_state,
act_hours=work_hours))
return return_values
def hours(self):
"""Return the number of hours worked on this engagement so far
"""
context = aq_inner(self.context)
catalog = getToolByName(context, 'portal_catalog')
time_brains = catalog(object_provides=ITimeentry.__identifier__,
path='/'.join(context.getPhysicalPath()),
sort_order='sortable_title')
return_hours = 0
for time_entry in time_brains:
timeentry = time_entry.getObject()
return_hours = return_hours + timeentry.timeamount
return return_hours
And my tests are:
from plone.app.testing import PloneSandboxLayer
from plone.app.testing import PLONE_FIXTURE
from plone.app.testing import IntegrationTesting
from plone.app.testing import applyProfile
from zope.configuration import xmlconfig
class InsEngagement(PloneSandboxLayer):
defaultBases = (PLONE_FIXTURE,)
def setUpZope(self, app, configurationContext):
# Load ZCML
import ins.engagement
xmlconfig.file('configure.zcml', ins.engagement,
context=configurationContext)
def setUpPloneSite(self, portal):
applyProfile(portal, 'ins.engagement:default')
INS_ENGAGEMENT_FIXTURE = InsEngagement()
INS_ENGAGEMENT_INTEGRATION_TESTING = \
IntegrationTesting(bases=(INS_ENGAGEMENT_FIXTURE,),
name="ins.engagement:Integration")
import unittest2 as unittest
from ins.engagement.tests.setupintegration import
INS_ENGAGEMENT_INTEGRATION_TESTING
from plone.app.testing import TEST_USER_NAME
from plone.app.testing import TEST_USER_PASSWORD
from plone.app.testing import setRoles
class IntegrationTestCase(unittest.TestCase):
layer = INS_ENGAGEMENT_INTEGRATION_TESTING
def test_adding(self):
portal = self.layer['portal']
setRoles(portal, TEST_USER_NAME, ['Manager'])
portal.invokeFactory('Folder', 'folder1')
f1 = portal['folder1']
f1.invokeFactory('ins.engagement.engagement', 'engagement1')
I also tried the following, but got the same traceback:
import unittest2 as unittest
from ins.engagement.tests.setupintegration import
INS_ENGAGEMENT_INTEGRATION_TESTING
from plone.app.testing import TEST_USER_NAME
from plone.app.testing import TEST_USER_PASSWORD
from plone.app.testing import setRoles
from zope.component import provideAdapter
from ins.engagement.engagement import IEngagement
from ins.engagement.engagement import LocalRoles
from borg.localrole.interfaces import ILocalRoleProvider
class IntegrationTestCase(unittest.TestCase):
layer = INS_ENGAGEMENT_INTEGRATION_TESTING
def test_adding(self):
portal = self.layer['portal']
setRoles(portal, TEST_USER_NAME, ['Manager'])
portal.invokeFactory('Folder', 'folder1')
f1 = portal['folder1']
provideAdapter(LocalRoles, adapts=[IEngagement,],
provides=ILocalRoleProvider)
f1.invokeFactory('ins.engagement.engagement', 'engagement1')
--
View this message in context:
http://plone.293351.n2.nabble.com/Problem-testing-local-roles-with-a-Dexterity-content-type-tp5715353p5715353.html
Sent from the Product Developers mailing list archive at Nabble.com.
_______________________________________________
Product-Developers mailing list
[email protected]
http://lists.plone.org/mailman/listinfo/product-developers