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

Reply via email to