[Checkins] SVN: CMF/trunk/C - added IConfigurableWorkflowTool

Yvo Schubbe y.2006_ at wcm-solutions.de
Wed Nov 15 06:39:01 EST 2006


Log message for revision 71137:
  - added IConfigurableWorkflowTool
  - added support for 'remove' attribute in import XML (http://www.zope.org/Collectors/CMF/457)
  - some related cleanup

Changed:
  U   CMF/trunk/CHANGES.txt
  U   CMF/trunk/CMFCore/WorkflowTool.py
  U   CMF/trunk/CMFCore/exportimport/tests/test_workflow.py
  U   CMF/trunk/CMFCore/exportimport/workflow.py
  U   CMF/trunk/CMFCore/interfaces/_tools.py
  U   CMF/trunk/CMFCore/tests/test_WorkflowTool.py

-=-
Modified: CMF/trunk/CHANGES.txt
===================================================================
--- CMF/trunk/CHANGES.txt	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CHANGES.txt	2006-11-15 11:38:59 UTC (rev 71137)
@@ -2,6 +2,12 @@
 
   New Features
 
+    - WorkflowTool: Added the IConfigurableWorkflowTool interface.
+      This change includes the new 'getDefaultChain' and 'listChainOverrides'
+      methods and an improved 'setChainForPortalTypes' method. The import
+      handler now supports the 'remove' attribute for removing overrides.
+      (http://www.zope.org/Collectors/CMF/457)
+
     - CMFCore.CachingPolicyManager: Implemented the old OFS.Cache.CacheManager
       API. Now objects other than CMF content or CMF templates can have their
       caching headers set by the caching policy manager with the same 

Modified: CMF/trunk/CMFCore/WorkflowTool.py
===================================================================
--- CMF/trunk/CMFCore/WorkflowTool.py	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CMFCore/WorkflowTool.py	2006-11-15 11:38:59 UTC (rev 71137)
@@ -27,6 +27,7 @@
 from zope.interface import implements
 
 from ActionProviderBase import ActionProviderBase
+from interfaces import IConfigurableWorkflowTool
 from interfaces import IWorkflowDefinition
 from interfaces import IWorkflowTool
 from interfaces.portal_workflow import portal_workflow as z2IWorkflowTool
@@ -49,7 +50,7 @@
     """ Mediator tool, mapping workflow objects
     """
 
-    implements(IWorkflowTool)
+    implements(IConfigurableWorkflowTool, IWorkflowTool)
     __implements__ = (z2IWorkflowTool, ActionProviderBase.__implements__)
 
     id = 'portal_workflow'
@@ -149,31 +150,8 @@
                             manage_tabs_message='Changed.')
 
     #
-    #   portal_workflow implementation.
+    #   'IActionProvider' interface methods
     #
-    security.declarePrivate('getCatalogVariablesFor')
-    def getCatalogVariablesFor(self, ob):
-
-        """ Returns a mapping of the catalog variables that apply to ob.
-
-        o Invoked by portal_catalog.
-
-        o Allows workflows to add variables to the catalog based on
-          workflow status, making it possible to implement queues.
-        """
-        wfs = self.getWorkflowsFor(ob)
-        if wfs is None:
-            return None
-        # Iterate through the workflows backwards so that
-        # earlier workflows can override later workflows.
-        wfs.reverse()
-        vars = {}
-        for wf in wfs:
-            v = wf.getCatalogVariablesFor(ob)
-            if v is not None:
-                vars.update(v)
-        return vars
-
     security.declarePrivate('listActions')
     def listActions(self, info=None, object=None):
 
@@ -215,16 +193,29 @@
                         actions.extend(a)
         return actions
 
+    #
+    #   'IWorkflowTool' interface methods
+    #
+    security.declarePrivate('getCatalogVariablesFor')
+    def getCatalogVariablesFor(self, ob):
+        """ Get a mapping of "workflow-relevant" attributes.
+        """
+        wfs = self.getWorkflowsFor(ob)
+        if wfs is None:
+            return None
+        # Iterate through the workflows backwards so that
+        # earlier workflows can override later workflows.
+        wfs.reverse()
+        vars = {}
+        for wf in wfs:
+            v = wf.getCatalogVariablesFor(ob)
+            if v is not None:
+                vars.update(v)
+        return vars
+
     security.declarePublic('doActionFor')
     def doActionFor(self, ob, action, wf_id=None, *args, **kw):
-
-        """ Execute the given workflow action for the object.
-
-        o Invoked by user interface code.
-
-        o Allows the user to request a workflow action.
-
-        o The workflow object must perform its own security checks.
+        """ Perform the given workflow action on 'ob'.
         """
         wfs = self.getWorkflowsFor(ob)
         if wfs is None:
@@ -251,14 +242,7 @@
 
     security.declarePublic('getInfoFor')
     def getInfoFor(self, ob, name, default=_marker, wf_id=None, *args, **kw):
-
-        """ Return a given workflow-specific property for an object.
-
-        o Invoked by user interface code.
-
-        o Allows the user to request information provided by the workflow.
-
-        o The workflow object must perform its own security checks.
+        """ Get the given bit of workflow information for the object.
         """
         if wf_id is None:
             wfs = self.getWorkflowsFor(ob)
@@ -295,9 +279,7 @@
 
     security.declarePrivate('notifyCreated')
     def notifyCreated(self, ob):
-
-        """ Notify all applicable workflows that an object has been created
-            and put in its new place.
+        """ Notify all applicable workflows that an object has been created.
         """
         wfs = self.getWorkflowsFor(ob)
         for wf in wfs:
@@ -306,14 +288,7 @@
 
     security.declarePrivate('notifyBefore')
     def notifyBefore(self, ob, action):
-
-        """ Notifies all applicable workflows of an action before it
-            happens, allowing veto by exception.
-
-        o Unless an exception is thrown, either a notifySuccess() or
-          notifyException() can be expected later on.
-
-        o The action usually corresponds to a method name.
+        """ Notify all applicable workflows of an action before it happens.
         """
         wfs = self.getWorkflowsFor(ob)
         for wf in wfs:
@@ -321,7 +296,6 @@
 
     security.declarePrivate('notifySuccess')
     def notifySuccess(self, ob, action, result=None):
-
         """ Notify all applicable workflows that an action has taken place.
         """
         wfs = self.getWorkflowsFor(ob)
@@ -330,7 +304,6 @@
 
     security.declarePrivate('notifyException')
     def notifyException(self, ob, action, exc):
-
         """ Notify all applicable workflows that an action failed.
         """
         wfs = self.getWorkflowsFor(ob)
@@ -339,10 +312,7 @@
 
     security.declarePrivate('getHistoryOf')
     def getHistoryOf(self, wf_id, ob):
-
-        """ Return the history of an object.
-
-        o Invoked by workflow definitions.
+        """ Get the history of an object for a given workflow.
         """
         if hasattr(aq_base(ob), 'workflow_history'):
             wfh = ob.workflow_history
@@ -351,10 +321,7 @@
 
     security.declarePrivate('getStatusOf')
     def getStatusOf(self, wf_id, ob):
-
-        """ Return the last entry of a workflow history.
-
-        o Invoked by workflow definitions.
+        """ Get the last element of a workflow history for a given workflow.
         """
         wfh = self.getHistoryOf(wf_id, ob)
         if wfh:
@@ -363,10 +330,7 @@
 
     security.declarePrivate('setStatusOf')
     def setStatusOf(self, wf_id, ob, status):
-
-        """ Append an entry to the workflow history.
-
-        o Invoked by workflow definitions.
+        """ Append a record to the workflow history of a given workflow.
         """
         wfh = None
         has_history = 0
@@ -385,31 +349,36 @@
         ob.workflow_history[wf_id] = tuple(wfh)
 
     #
-    #   Administration methods
+    #   'IConfigurableWorkflowTool' interface methods
     #
-    security.declareProtected( ManagePortal, 'setDefaultChain')
+    security.declareProtected(ManagePortal, 'setDefaultChain')
     def setDefaultChain(self, default_chain):
-
-        """ Set the default chain for this tool
+        """ Set the default chain for this tool.
         """
         default_chain = default_chain.replace(',', ' ')
         ids = []
         for wf_id in default_chain.split(' '):
             if wf_id:
                 if not self.getWorkflowById(wf_id):
-                    raise ValueError, ( '"%s" is not a workflow ID.' % wf_id)
+                    raise ValueError('"%s" is not a workflow ID.' % wf_id)
                 ids.append(wf_id)
 
         self._default_chain = tuple(ids)
 
-    security.declareProtected( ManagePortal, 'setChainForPortalTypes')
+    security.declareProtected(ManagePortal, 'setChainForPortalTypes')
     def setChainForPortalTypes(self, pt_names, chain, verify=True):
-        """ Set a chain for a specific portal type.
+        """ Set a chain for specific portal types.
         """
         cbt = self._chains_by_type
         if cbt is None:
             self._chains_by_type = cbt = PersistentMapping()
 
+        if chain is None:
+            for type_id in pt_names:
+                if cbt.has_key(type_id):
+                    del cbt[type_id]
+            return
+
         if isinstance(chain, basestring):
             chain = [ wf.strip() for wf in chain.split(',') if wf.strip() ]
 
@@ -420,9 +389,48 @@
                 continue
             cbt[type_id] = tuple(chain)
 
-    security.declareProtected( ManagePortal, 'updateRoleMappings')
-    def updateRoleMappings(self, REQUEST=None):
+    security.declarePrivate('getDefaultChain')
+    def getDefaultChain(self):
+        """ Get the default chain for this tool.
+        """
+        return self._default_chain
 
+    security.declarePrivate('listChainOverrides')
+    def listChainOverrides(self):
+        """ List portal type specific chain overrides.
+        """
+        cbt = self._chains_by_type
+        return cbt and sorted(cbt.items()) or ()
+
+    security.declarePrivate('getChainFor')
+    def getChainFor(self, ob):
+        """ Get the chain that applies to the given object.
+        """
+        cbt = self._chains_by_type
+        if isinstance(ob, basestring):
+            pt = ob
+        elif hasattr(aq_base(ob), 'getPortalTypeName'):
+            pt = ob.getPortalTypeName()
+        else:
+            pt = None
+
+        if pt is None:
+            return ()
+
+        chain = None
+        if cbt is not None:
+            chain = cbt.get(pt, None)
+            # Note that if chain is not in cbt or has a value of
+            # None, we use a default chain.
+        if chain is None:
+            return self.getDefaultChain()
+        return chain
+
+    #
+    #   Other methods
+    #
+    security.declareProtected(ManagePortal, 'updateRoleMappings')
+    def updateRoleMappings(self, REQUEST=None):
         """ Allow workflows to update the role-permission mappings.
         """
         wfs = {}
@@ -451,8 +459,7 @@
 
     security.declarePrivate('getDefaultChainFor')
     def getDefaultChainFor(self, ob):
-
-        """ Return the default chain, if applicable, for ob.
+        """ Get the default chain, if applicable, for ob.
         """
         types_tool = getToolByName( self, 'portal_types', None )
         if ( types_tool is not None
@@ -461,35 +468,6 @@
 
         return ()
 
-    security.declarePrivate('getChainFor')
-    def getChainFor(self, ob):
-
-        """ Returns the chain that applies to the given object.
-            If we get a string as the ob parameter, use it as
-            the portal_type.
-        """
-        cbt = self._chains_by_type
-        if isinstance(ob, basestring):
-            pt = ob
-        elif hasattr(aq_base(ob), 'getPortalTypeName'):
-            pt = ob.getPortalTypeName()
-        else:
-            pt = None
-
-        if pt is None:
-            return ()
-
-        chain = None
-        if cbt is not None:
-            chain = cbt.get(pt, None)
-            # Note that if chain is not in cbt or has a value of
-            # None, we use a default chain.
-        if chain is None:
-            chain = self.getDefaultChainFor(ob)
-            if chain is None:
-                return ()
-        return chain
-
     security.declarePrivate('getWorkflowIds')
     def getWorkflowIds(self):
 

Modified: CMF/trunk/CMFCore/exportimport/tests/test_workflow.py
===================================================================
--- CMF/trunk/CMFCore/exportimport/tests/test_workflow.py	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CMFCore/exportimport/tests/test_workflow.py	2006-11-15 11:38:59 UTC (rev 71137)
@@ -32,7 +32,7 @@
 from Products.GenericSetup.utils import BodyAdapterBase
 
 from Products.CMFCore.interfaces import IWorkflowDefinition
-from Products.CMFCore.interfaces import IWorkflowTool
+from Products.CMFCore.interfaces import IConfigurableWorkflowTool
 
 _DUMMY_ZCML = """\
 <configure
@@ -109,10 +109,19 @@
 </object>
 """
 
+_FRAGMENT_IMPORT = """\
+<?xml version="1.0"?>
+<object name="portal_workflow">
+ <bindings>
+  <type type_id="sometype" remove=""/>
+ </bindings>
+</object>
+"""
 
+
 class DummyWorkflowTool(Folder):
 
-    implements(IWorkflowTool)
+    implements(IConfigurableWorkflowTool)
 
     meta_type = 'Dummy Workflow Tool'
 
@@ -127,17 +136,26 @@
     def getWorkflowById(self, workflow_id):
         return self._getOb(workflow_id)
 
+    def getDefaultChain(self):
+        return self._default_chain
+
     def setDefaultChain(self, chain):
         chain = chain.replace(',', ' ')
         self._default_chain = tuple(chain.split())
 
+    def listChainOverrides(self):
+        return sorted(self._chains_by_type.items())
+
     def setChainForPortalTypes(self, pt_names, chain, verify=True):
+        if chain is None:
+            for pt_name in pt_names:
+                if pt_name in self._chains_by_type:
+                    del self._chains_by_type[pt_name]
+            return
+
         chain = chain.replace(',', ' ')
         chain = tuple(chain.split())
 
-        if self._chains_by_type is None:
-            self._chains_by_type = {}
-
         for pt_name in pt_names:
             self._chains_by_type[pt_name] = chain
 
@@ -245,6 +263,7 @@
 
     _BINDINGS_TOOL_EXPORT = _BINDINGS_TOOL_EXPORT
     _EMPTY_TOOL_EXPORT = _EMPTY_TOOL_EXPORT
+    _FRAGMENT_IMPORT = _FRAGMENT_IMPORT
 
     def test_empty_default_purge(self):
         from Products.CMFCore.exportimport.workflow import importWorkflowTool
@@ -359,7 +378,34 @@
         self.assertEqual(wf_tool._chains_by_type['anothertype'],
                          (WF_ID_NON % 3,))
 
+    def test_fragment_skip_purge(self):
+        from Products.CMFCore.exportimport.workflow import importWorkflowTool
 
+        WF_ID_NON = 'non_dcworkflow_%s'
+        WF_TITLE_NON = 'Non-DCWorkflow #%s'
+
+        site = self._initSite()
+        wf_tool = site.portal_workflow
+
+        for i in range(4):
+            nondcworkflow = DummyWorkflow(WF_TITLE_NON % i)
+            nondcworkflow.title = WF_TITLE_NON % i
+            wf_tool._setObject(WF_ID_NON % i, nondcworkflow)
+
+        wf_tool._default_chain = (WF_ID_NON % 1,)
+        wf_tool._chains_by_type['sometype'] = (WF_ID_NON % 2,)
+        self.assertEqual(len(wf_tool.objectIds()), 4)
+
+        context = DummyImportContext(site, False)
+        context._files['workflows.xml'] = self._FRAGMENT_IMPORT
+        importWorkflowTool(context)
+
+        self.assertEqual(len(wf_tool.objectIds()), 4)
+        self.assertEqual(len(wf_tool._default_chain), 1)
+        self.assertEqual(wf_tool._default_chain[0], WF_ID_NON % 1)
+        self.assertEqual(len(wf_tool._chains_by_type), 0)
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(WorkflowToolXMLAdapterTests),

Modified: CMF/trunk/CMFCore/exportimport/workflow.py
===================================================================
--- CMF/trunk/CMFCore/exportimport/workflow.py	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CMFCore/exportimport/workflow.py	2006-11-15 11:38:59 UTC (rev 71137)
@@ -24,7 +24,7 @@
 from Products.GenericSetup.utils import PropertyManagerHelpers
 from Products.GenericSetup.utils import XMLAdapterBase
 
-from Products.CMFCore.interfaces import IWorkflowTool
+from Products.CMFCore.interfaces import IConfigurableWorkflowTool
 from Products.CMFCore.utils import getToolByName
 
 
@@ -34,7 +34,7 @@
     """XML im- and exporter for WorkflowTool.
     """
 
-    adapts(IWorkflowTool, ISetupEnviron)
+    adapts(IConfigurableWorkflowTool, ISetupEnviron)
 
     _LOGGER_ID = 'workflow'
 
@@ -69,31 +69,28 @@
         fragment = self._doc.createDocumentFragment()
         node = self._doc.createElement('bindings')
         child = self._doc.createElement('default')
-        chain = self.context._default_chain
+        chain = self.context.getDefaultChain()
         for workflow_id in chain:
             sub = self._doc.createElement('bound-workflow')
             sub.setAttribute('workflow_id', workflow_id)
             child.appendChild(sub)
         node.appendChild(child)
-        cbt = self.context._chains_by_type
-        if cbt:
-            overrides = cbt.items()
-            overrides.sort()
-            for type_id, chain in overrides:
-                child = self._doc.createElement('type')
-                child.setAttribute('type_id', type_id)
-                for workflow_id in chain:
-                    sub = self._doc.createElement('bound-workflow')
-                    sub.setAttribute('workflow_id', workflow_id)
-                    child.appendChild(sub)
-                node.appendChild(child)
+        for type_id, chain in self.context.listChainOverrides():
+            child = self._doc.createElement('type')
+            child.setAttribute('type_id', type_id)
+            for workflow_id in chain:
+                sub = self._doc.createElement('bound-workflow')
+                sub.setAttribute('workflow_id', workflow_id)
+                child.appendChild(sub)
+            node.appendChild(child)
         fragment.appendChild(node)
         return fragment
 
     def _purgeChains(self):
         self.context.setDefaultChain('')
-        if self.context._chains_by_type is not None:
-            self.context._chains_by_type.clear()
+        for type_id, chain in self.context.listChainOverrides():
+            self.context.setChainForPortalTypes((type_id,), None,
+                                                verify=False)
 
     def _initChains(self, node):
         for child in node.childNodes:
@@ -104,8 +101,12 @@
                     self.context.setDefaultChain(self._getChain(sub))
                 if sub.nodeName == 'type':
                     type_id = str(sub.getAttribute('type_id'))
-                    self.context.setChainForPortalTypes((type_id,),
-                                            self._getChain(sub), verify=False)
+                    if sub.hasAttribute('remove'):
+                        chain = None
+                    else:
+                        chain = self._getChain(sub)
+                    self.context.setChainForPortalTypes((type_id,), chain,
+                                                        verify=False)
 
     def _getChain(self, node):
         workflow_ids = []

Modified: CMF/trunk/CMFCore/interfaces/_tools.py
===================================================================
--- CMF/trunk/CMFCore/interfaces/_tools.py	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CMFCore/interfaces/_tools.py	2006-11-15 11:38:59 UTC (rev 71137)
@@ -1545,7 +1545,7 @@
             )
 
     def getCatalogVariablesFor(ob):
-        """ Return a mapping of "workflow-relevant" attributes.
+        """ Get a mapping of "workflow-relevant" attributes.
 
         o Invoked by 'portal_catalog' when indexing content.
 
@@ -1575,7 +1575,7 @@
         """
 
     def getInfoFor(ob, name, default=_marker, wf_id=None):
-        """ Return the given bit of workflow information for the object.
+        """ Get the given bit of workflow information for the object.
 
         o 'ob' is the target object.
 
@@ -1644,7 +1644,7 @@
         """
 
     def getHistoryOf(wf_id, ob):
-        """ Returns the history of an object for a given workflow.
+        """ Get the history of an object for a given workflow.
 
         o 'wf_id' is the id of the selected workflow.
 
@@ -1656,7 +1656,7 @@
         """
 
     def getStatusOf(wf_id, ob):
-        """ Return the last element of a workflow history for a given workflow.
+        """ Get the last element of a workflow history for a given workflow.
 
         o 'wf_id' is the id of the selected workflow.
 
@@ -1682,6 +1682,47 @@
         """
 
 
+class IConfigurableWorkflowTool(IWorkflowTool):
+
+    """ Manage workflow tool settings.
+    """
+
+    def setDefaultChain(default_chain):
+        """ Set the default chain for this tool.
+
+        o Permission:  Manage portal
+        """
+
+    def setChainForPortalTypes(pt_names, chain, verify=True):
+        """ Set a chain for specific portal types.
+
+        o If chain is None, set the chain for the portal types to be the
+          default chain.
+
+        o Permission:  Manage portal
+        """
+
+    def getDefaultChain():
+        """ Get the default chain for this tool.
+
+        o Permission:  Private (Python only)
+        """
+
+    def listChainOverrides():
+        """ List portal type specific chain overrides.
+
+        o Permission:  Private (Python only)
+        """
+
+    def getChainFor(ob):
+        """ Get the chain that applies to the given object.
+
+        o If 'ob' is a string, it is used as portal type name.
+
+        o Permission:  Private (Python only)
+        """
+
+
 class IWorkflowDefinition(Interface):
 
     """Plugin interface for workflow definitions managed by IWorkflowTool.

Modified: CMF/trunk/CMFCore/tests/test_WorkflowTool.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_WorkflowTool.py	2006-11-15 09:26:18 UTC (rev 71136)
+++ CMF/trunk/CMFCore/tests/test_WorkflowTool.py	2006-11-15 11:38:59 UTC (rev 71137)
@@ -173,10 +173,12 @@
     def test_z3interfaces(self):
         from zope.interface.verify import verifyClass
         from Products.CMFCore.interfaces import IActionProvider
+        from Products.CMFCore.interfaces import IConfigurableWorkflowTool
         from Products.CMFCore.interfaces import IWorkflowTool
         from Products.CMFCore.WorkflowTool import WorkflowTool
 
         verifyClass(IActionProvider, WorkflowTool)
+        verifyClass(IConfigurableWorkflowTool, WorkflowTool)
         verifyClass(IWorkflowTool, WorkflowTool)
 
     def test_empty( self ):
@@ -215,6 +217,8 @@
 
         tool = self._makeWithTypesAndChain()
         self.assertEquals( len( tool.getDefaultChainFor( None ) ), 0 )
+        self.assertEquals( len( tool.getDefaultChain() ), 1 )
+        self.assertEquals( len( tool.listChainOverrides() ), 1 )
         self.assertEquals( len( tool.getChainFor( None ) ), 0 )
         self.assertEquals( len( tool.getCatalogVariablesFor( None ) ), 0 )
 
@@ -223,6 +227,8 @@
         tool = self._makeWithTypesAndChain()
         dummy = DummyNotReallyContent( 'doh' )
         self.assertEquals( len( tool.getDefaultChainFor( dummy ) ), 0 )
+        self.assertEquals( len( tool.getDefaultChain() ), 1 )
+        self.assertEquals( len( tool.listChainOverrides() ), 1 )
         self.assertEquals( len( tool.getChainFor( dummy ) ), 0 )
         self.assertEquals( len( tool.getCatalogVariablesFor( dummy ) ), 0 )
 
@@ -231,10 +237,11 @@
         tool = self._makeWithTypes()
         dummy = DummyContent( 'dummy' )
         self.assertEquals( len( tool.getDefaultChainFor( dummy ) ), 1 )
+        self.assertEquals( len( tool.getDefaultChain() ), 1 )
+        self.assertEquals( len( tool.listChainOverrides() ), 0 )
         self.assertEquals( len( tool.getChainFor( dummy ) ), 1 )
         self.assertEquals( len( tool.getCatalogVariablesFor( dummy ) ), 0 )
-        self.assertEquals( tool.getDefaultChainFor( dummy )
-                         , tool.getChainFor( dummy ) )
+        self.assertEquals( tool.getDefaultChain(), tool.getChainFor( dummy ) )
 
     def test_content_own_chain( self ):
 
@@ -243,6 +250,8 @@
         dummy = DummyContent( 'dummy' )
 
         self.assertEquals( len( tool.getDefaultChainFor( dummy ) ), 1 )
+        self.assertEquals( len( tool.getDefaultChain() ), 1 )
+        self.assertEquals( len( tool.listChainOverrides() ), 1 )
         chain = tool.getChainFor( dummy )
         self.assertEquals( len( chain ), 2 )
         self.failUnless( 'a' in chain )
@@ -256,6 +265,7 @@
     def test_setChainForPortalTypes(self):
 
         tool = self._makeWithTypes()
+        tool.setDefaultChain('b, a')
         dummy = DummyContent('dummy')
 
         tool.setChainForPortalTypes( ('Dummy Content',), ('a', 'b') )
@@ -268,6 +278,9 @@
         tool.setChainForPortalTypes( ('Dummy Content',), '' )
         self.assertEquals( tool.getChainFor(dummy), () )
 
+        tool.setChainForPortalTypes( ('Dummy Content',), None )
+        self.assertEquals( tool.getChainFor(dummy), ('b', 'a') )
+
     def test_getCatalogVariablesFor( self ):
 
         tool = self._makeWithTypesAndChain()



More information about the Checkins mailing list