Back to index

plone3  3.1.7
test_actions.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """Actions tool node adapter unit tests.
00014 
00015 $Id: test_actions.py 77004 2007-06-24 08:57:54Z yuppie $
00016 """
00017 
00018 import unittest
00019 import Testing
00020 
00021 from Acquisition import aq_parent
00022 from Acquisition import Implicit
00023 from OFS.OrderedFolder import OrderedFolder
00024 from zope.interface import implements
00025 from zope.interface import Interface
00026 
00027 from Products.CMFCore.ActionProviderBase import ActionProviderBase
00028 from Products.CMFCore.interfaces import IActionsTool
00029 from Products.CMFCore.interfaces.portal_actions \
00030     import ActionProvider as IActionProvider
00031 from Products.CMFCore.testing import ExportImportZCMLLayer
00032 from Products.CMFCore.tests.base.dummy import DummySite
00033 from Products.GenericSetup.testing import BodyAdapterTestCase
00034 from Products.GenericSetup.testing import NodeAdapterTestCase
00035 from Products.GenericSetup.tests.common import BaseRegistryTests
00036 from Products.GenericSetup.tests.common import DummyExportContext
00037 from Products.GenericSetup.tests.common import DummyImportContext
00038 
00039 _ACTION_XML = """\
00040 <object name="foo_action" meta_type="CMF Action">
00041  <property name="title">Foo</property>
00042  <property name="description"></property>
00043  <property name="url_expr">string:${object_url}/foo</property>
00044  <property name="icon_expr"></property>
00045  <property name="available_expr">python:1</property>
00046  <property name="permissions"/>
00047  <property name="visible">True</property>
00048 </object>
00049 """
00050 
00051 _ACTIONCATEGORY_XML = """\
00052 <object name="foo_category" meta_type="CMF Action Category">
00053  <property name="title"></property>
00054  <object name="foo_action" meta_type="CMF Action">
00055   <property name="title"></property>
00056   <property name="description"></property>
00057   <property name="url_expr"></property>
00058   <property name="icon_expr"></property>
00059   <property name="available_expr"></property>
00060   <property name="permissions"/>
00061   <property name="visible">True</property>
00062  </object>
00063 </object>
00064 """
00065 
00066 _ACTIONSTOOL_BODY = """\
00067 <?xml version="1.0"?>
00068 <object name="portal_actions" meta_type="CMF Actions Tool"
00069    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
00070  <action-provider name="portal_actions"/>
00071  <object name="foo_category" meta_type="CMF Action Category">
00072   <property name="title"></property>
00073   <object name="foo_action" meta_type="CMF Action" i18n:domain="foo_domain">
00074    <property name="title" i18n:translate=""></property>
00075    <property name="description" i18n:translate=""></property>
00076    <property name="url_expr"></property>
00077    <property name="icon_expr"></property>
00078    <property name="available_expr"></property>
00079    <property name="permissions"/>
00080    <property name="visible">True</property>
00081   </object>
00082  </object>
00083 </object>
00084 """
00085 
00086 _EMPTY_EXPORT = """\
00087 <?xml version="1.0"?>
00088 <object name="portal_actions" meta_type="CMF Actions Tool"
00089    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
00090  <action-provider name="portal_actions"/>
00091 </object>
00092 """
00093 
00094 _NORMAL_EXPORT = """\
00095 <?xml version="1.0"?>
00096 <object name="portal_actions" meta_type="CMF Actions Tool"
00097    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
00098  <action-provider name="portal_actions"/>
00099  <action-provider name="portal_foo">
00100   <action action_id="foo"
00101           title="Foo"
00102           url_expr="string:${object_url}/foo"
00103           condition_expr="python:1"
00104           category="dummy"
00105           visible="True"/>
00106  </action-provider>
00107  <action-provider name="portal_bar">
00108   <action action_id="bar"
00109           title="Bar"
00110           url_expr="string:${object_url}/bar"
00111           condition_expr="python:0"
00112           category="dummy"
00113           visible="False">
00114    <permission>Manage portal</permission>
00115   </action>
00116  </action-provider>
00117 </object>
00118 """
00119 
00120 _NEWSYTLE_EXPORT = """\
00121 <?xml version="1.0"?>
00122 <object name="portal_actions" meta_type="CMF Actions Tool"
00123    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
00124  <action-provider name="portal_actions"/>
00125  <object name="dummy" meta_type="CMF Action Category">
00126   <property name="title"></property>
00127   <object name="foo" meta_type="CMF Action">
00128    <property name="title">Foo</property>
00129    <property name="description"></property>
00130    <property name="url_expr">string:${object_url}/foo</property>
00131    <property name="icon_expr"></property>
00132    <property name="available_expr">python:1</property>
00133    <property name="permissions"></property>
00134    <property name="visible">True</property>
00135   </object>
00136   <object name="bar" meta_type="CMF Action">
00137    <property name="title">Bar</property>
00138    <property name="description"></property>
00139    <property name="url_expr">string:${object_url}/bar</property>
00140    <property name="icon_expr"></property>
00141    <property name="available_expr">python:0</property>
00142    <property name="permissions">
00143     <element value="Manage portal"/>
00144    </property>
00145    <property name="visible">False</property>
00146   </object>
00147  </object>
00148 </object>
00149 """
00150 
00151 _I18N_IMPORT = """\
00152 <?xml version="1.0"?>
00153 <object name="portal_actions" meta_type="CMF Actions Tool"
00154    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
00155  <action-provider name="portal_actions"/>
00156  <object name="dummy" meta_type="CMF Action Category">
00157   <property name="title"></property>
00158   <object name="foo" meta_type="CMF Action" i18n:domain="foo_domain">
00159    <property name="title" i18n:translate="">Foo</property>
00160    <property name="description" i18n:translate=""></property>
00161    <property name="url_expr">string:${object_url}/foo</property>
00162    <property name="icon_expr"></property>
00163    <property name="available_expr">python:1</property>
00164    <property name="permissions"></property>
00165    <property name="visible">True</property>
00166   </object>
00167  </object>
00168 </object>
00169 """
00170 
00171 _INSERT_IMPORT = """\
00172 <?xml version="1.0"?>
00173 <object name="portal_actions">
00174  <object name="dummy">
00175  <object name="spam" meta_type="CMF Action" insert-before="*">
00176   <property name="title">Spam</property>
00177   <property name="description"></property>
00178   <property name="url_expr">string:${object_url}/spam</property>
00179   <property name="icon_expr">string:spam_icon.png</property>
00180   <property name="available_expr"></property>
00181   <property name="permissions">
00182    <element value="View" /></property>
00183   <property name="visible">True</property>
00184  </object>
00185  <object name="foo" insert-after="*">
00186   <property name="icon_expr">string:foo_icon.png</property>
00187  </object>
00188  </object>
00189 </object>
00190 """
00191 
00192 _REMOVE_IMPORT = """\
00193 <?xml version="1.0"?>
00194 <object name="portal_actions">
00195  <action-provider name="portal_actions" remove=""/>
00196  <action-provider name="not_existing" remove=""/>
00197  <action-provider name="portal_bar" remove=""/>
00198 </object>
00199 """
00200 
00201 
00202 class DummyTool(OrderedFolder, ActionProviderBase):
00203 
00204     __implements__ = IActionProvider
00205 
00206 
00207 class DummyUser(Implicit):
00208 
00209     def getId(self):
00210         return 'dummy'
00211 
00212 
00213 class DummyMembershipTool(DummyTool):
00214 
00215     def isAnonymousUser(self):
00216         return False
00217 
00218     def getAuthenticatedMember(self):
00219         return DummyUser().__of__(aq_parent(self))
00220 
00221 
00222 class DummyActionsTool(DummyTool):
00223 
00224     implements(IActionsTool)
00225     id = 'portal_actions'
00226     meta_type = 'CMF Actions Tool'
00227 
00228     def __init__(self):
00229         self._providers = []
00230 
00231     def addActionProvider(self, provider_name):
00232         self._providers.append(provider_name)
00233 
00234     def listActionProviders(self):
00235         return self._providers[:]
00236 
00237     def deleteActionProvider(self, provider_name):
00238         self._providers = [ x for x in self._providers if x != provider_name ]
00239 
00240 
00241 class ActionNodeAdapterTests(NodeAdapterTestCase):
00242 
00243     layer = ExportImportZCMLLayer
00244 
00245     def _getTargetClass(self):
00246         from Products.CMFCore.exportimport.actions import ActionNodeAdapter
00247 
00248         return ActionNodeAdapter
00249 
00250     def _populate(self, obj):
00251         obj._setPropValue('title', 'Foo')
00252         obj._setPropValue('url_expr', 'string:${object_url}/foo')
00253         obj._setPropValue('available_expr', 'python:1')
00254 
00255     def _verifyImport(self, obj):
00256         self.assertEqual(type(obj.title), str)
00257         self.assertEqual(obj.title, 'Foo')
00258         self.assertEqual(type(obj.description), str)
00259         self.assertEqual(obj.description, '')
00260         self.assertEqual(type(obj.url_expr), str)
00261         self.assertEqual(obj.url_expr, 'string:${object_url}/foo')
00262         self.assertEqual(type(obj.icon_expr), str)
00263         self.assertEqual(obj.icon_expr, '')
00264         self.assertEqual(type(obj.available_expr), str)
00265         self.assertEqual(obj.available_expr, 'python:1')
00266         self.assertEqual(type(obj.permissions), tuple)
00267         self.assertEqual(obj.permissions, ())
00268         self.assertEqual(type(obj.visible), bool)
00269         self.assertEqual(obj.visible, True)
00270 
00271     def setUp(self):
00272         from Products.CMFCore.ActionInformation import Action
00273 
00274         NodeAdapterTestCase.setUp(self)
00275         self._obj = Action('foo_action')
00276         self._XML = _ACTION_XML
00277 
00278 
00279 class ActionCategoryNodeAdapterTests(NodeAdapterTestCase):
00280 
00281     layer = ExportImportZCMLLayer
00282 
00283     def _getTargetClass(self):
00284         from Products.CMFCore.exportimport.actions \
00285                 import ActionCategoryNodeAdapter
00286 
00287         return ActionCategoryNodeAdapter
00288 
00289     def _populate(self, obj):
00290         from Products.CMFCore.ActionInformation import Action
00291 
00292         obj._setObject('foo_action', Action('foo_action'))
00293 
00294     def _verifyImport(self, obj):
00295         self.assertEqual(type(obj.title), str)
00296         self.assertEqual(obj.title, '')
00297 
00298     def setUp(self):
00299         from Products.CMFCore.ActionInformation import ActionCategory
00300 
00301         NodeAdapterTestCase.setUp(self)
00302         self._obj = ActionCategory('foo_category')
00303         self._XML = _ACTIONCATEGORY_XML
00304 
00305 
00306 class ActionsToolXMLAdapterTests(BodyAdapterTestCase):
00307 
00308     layer = ExportImportZCMLLayer
00309 
00310     def _getTargetClass(self):
00311         from Products.CMFCore.exportimport.actions \
00312                 import ActionsToolXMLAdapter
00313 
00314         return ActionsToolXMLAdapter
00315 
00316     def _populate(self, obj):
00317         from Products.CMFCore.ActionInformation import Action
00318         from Products.CMFCore.ActionInformation import ActionCategory
00319 
00320         obj._setObject('foo_category', ActionCategory('foo_category'))
00321         obj.action_providers = ('portal_actions',)
00322         obj.foo_category._setObject('foo_action', Action('foo_action'))
00323         obj.foo_category.foo_action.i18n_domain = 'foo_domain'
00324 
00325     def _verifyImport(self, obj):
00326         self.assertEqual(type(obj.action_providers), tuple)
00327         self.assertEqual(obj.action_providers, ('portal_actions',))
00328         self.assertEqual(type(obj.action_providers[0]), str)
00329         self.assertEqual(obj.action_providers[0], 'portal_actions')
00330 
00331     def setUp(self):
00332         from Products.CMFCore.ActionsTool import ActionsTool
00333 
00334         BodyAdapterTestCase.setUp(self)
00335         site = DummySite('site')
00336         site._setObject('portal_actions', ActionsTool('portal_actions'))
00337         self._obj = site.portal_actions
00338         self._BODY = _ACTIONSTOOL_BODY
00339 
00340 
00341 class _ActionSetup(BaseRegistryTests):
00342 
00343     def _initSite(self, foo=2, bar=2):
00344         self.root.site = DummySite('site')
00345         site = self.root.site
00346         site.portal_membership = DummyMembershipTool()
00347 
00348         site.portal_actions = DummyActionsTool()
00349         site.portal_actions.addActionProvider('portal_actions')
00350 
00351         if foo > 0:
00352             site.portal_foo = DummyTool()
00353 
00354         if foo > 1:
00355             site.portal_foo.addAction(id='foo',
00356                                       name='Foo',
00357                                       action='foo',
00358                                       condition='python:1',
00359                                       permission=(),
00360                                       category='dummy',
00361                                       visible=1)
00362             site.portal_actions.addActionProvider('portal_foo')
00363 
00364         if bar > 0:
00365             site.portal_bar = DummyTool()
00366 
00367         if bar > 1:
00368             site.portal_bar.addAction(id='bar',
00369                                       name='Bar',
00370                                       action='bar',
00371                                       condition='python:0',
00372                                       permission=('Manage portal',),
00373                                       category='dummy',
00374                                       visible=0)
00375             site.portal_actions.addActionProvider('portal_bar')
00376 
00377         return site
00378 
00379 
00380 class exportActionProvidersTests(_ActionSetup):
00381 
00382     layer = ExportImportZCMLLayer
00383 
00384     def test_unchanged(self):
00385         from Products.CMFCore.exportimport.actions \
00386                 import exportActionProviders
00387 
00388         site = self._initSite(0, 0)
00389         context = DummyExportContext(site)
00390         exportActionProviders(context)
00391 
00392         self.assertEqual(len(context._wrote), 1)
00393         filename, text, content_type = context._wrote[0]
00394         self.assertEqual(filename, 'actions.xml')
00395         self._compareDOM(text, _EMPTY_EXPORT)
00396         self.assertEqual(content_type, 'text/xml')
00397 
00398     def test_normal(self):
00399         from Products.CMFCore.exportimport.actions \
00400                 import exportActionProviders
00401 
00402         site = self._initSite()
00403         context = DummyExportContext(site)
00404         exportActionProviders(context)
00405 
00406         self.assertEqual(len(context._wrote), 1)
00407         filename, text, content_type = context._wrote[0]
00408         self.assertEqual(filename, 'actions.xml')
00409         self._compareDOM(text, _NORMAL_EXPORT)
00410         self.assertEqual(content_type, 'text/xml')
00411 
00412 
00413 class importActionProvidersTests(_ActionSetup):
00414 
00415     layer = ExportImportZCMLLayer
00416 
00417     def test_empty_default_purge(self):
00418         from Products.CMFCore.exportimport.actions \
00419                 import importActionProviders
00420 
00421         site = self._initSite(2, 0)
00422         atool = site.portal_actions
00423 
00424         self.assertEqual(len(atool.listActionProviders()), 2)
00425         self.failUnless('portal_foo' in atool.listActionProviders())
00426         self.failUnless('portal_actions' in atool.listActionProviders())
00427 
00428         context = DummyImportContext(site)
00429         context._files['actions.xml'] = _EMPTY_EXPORT
00430         importActionProviders(context)
00431 
00432         self.assertEqual(len(atool.listActionProviders()), 1)
00433         self.failIf('portal_foo' in atool.listActionProviders())
00434         self.failUnless('portal_actions' in atool.listActionProviders())
00435         self.assertEqual(len(atool.objectIds()), 0)
00436 
00437     def test_empty_explicit_purge(self):
00438         from Products.CMFCore.exportimport.actions \
00439                 import importActionProviders
00440 
00441         site = self._initSite(2, 0)
00442         atool = site.portal_actions
00443 
00444         self.assertEqual(len(atool.listActionProviders()), 2)
00445         self.failUnless('portal_foo' in atool.listActionProviders())
00446         self.failUnless('portal_actions' in atool.listActionProviders())
00447 
00448         context = DummyImportContext(site, True)
00449         context._files['actions.xml'] = _EMPTY_EXPORT
00450         importActionProviders(context)
00451 
00452         self.assertEqual(len(atool.listActionProviders()), 1)
00453         self.failIf('portal_foo' in atool.listActionProviders())
00454         self.failUnless('portal_actions' in atool.listActionProviders())
00455         self.assertEqual(len(atool.objectIds()), 0)
00456 
00457     def test_empty_skip_purge(self):
00458         from Products.CMFCore.exportimport.actions \
00459                 import importActionProviders
00460 
00461         site = self._initSite(2, 0)
00462         atool = site.portal_actions
00463 
00464         self.assertEqual(len(atool.listActionProviders()), 2)
00465         self.failUnless('portal_foo' in atool.listActionProviders())
00466         self.failUnless('portal_actions' in atool.listActionProviders())
00467 
00468         context = DummyImportContext(site, False)
00469         context._files['actions.xml'] = _EMPTY_EXPORT
00470         importActionProviders(context)
00471 
00472         self.assertEqual(len(atool.listActionProviders()), 2)
00473         self.failUnless('portal_foo' in atool.listActionProviders())
00474         self.failUnless('portal_actions' in atool.listActionProviders())
00475 
00476     def test_normal(self):
00477         from Products.CMFCore.exportimport.actions \
00478                 import exportActionProviders
00479         from Products.CMFCore.exportimport.actions \
00480                 import importActionProviders
00481 
00482         site = self._initSite(1, 1)
00483         atool = site.portal_actions
00484         foo = site.portal_foo
00485         bar = site.portal_bar
00486 
00487         self.assertEqual(len(atool.listActionProviders()), 1)
00488         self.failIf('portal_foo' in atool.listActionProviders())
00489         self.failIf(foo.listActions())
00490         self.failIf('portal_bar' in atool.listActionProviders())
00491         self.failIf(bar.listActions())
00492         self.failUnless('portal_actions' in atool.listActionProviders())
00493 
00494         context = DummyImportContext(site)
00495         context._files['actions.xml'] = _NORMAL_EXPORT
00496         importActionProviders(context)
00497 
00498         self.assertEqual(len(atool.listActionProviders()), 1)
00499         self.failIf('portal_foo' in atool.listActionProviders())
00500         self.failUnless('portal_actions' in atool.listActionProviders())
00501 
00502         self.assertEqual(len(atool.objectIds()), 1)
00503         self.failUnless('dummy' in atool.objectIds())
00504         self.assertEqual(len(atool.dummy.objectIds()) , 2)
00505         self.failUnless('foo' in atool.dummy.objectIds())
00506         self.failUnless('bar' in atool.dummy.objectIds())
00507         self.failIf(foo.listActions())
00508         self.failIf(bar.listActions())
00509 
00510         # complete the roundtrip
00511         context = DummyExportContext(site)
00512         exportActionProviders(context)
00513 
00514         self.assertEqual(len(context._wrote), 1)
00515         filename, text, content_type = context._wrote[0]
00516         self.assertEqual(filename, 'actions.xml')
00517         self._compareDOM(text, _NEWSYTLE_EXPORT)
00518         self.assertEqual(content_type, 'text/xml')
00519 
00520     def test_i18n(self):
00521         from Products.CMFCore.exportimport.actions \
00522                 import exportActionProviders
00523         from Products.CMFCore.exportimport.actions \
00524                 import importActionProviders
00525 
00526         site = self._initSite(0, 0)
00527         atool = site.portal_actions
00528 
00529         context = DummyImportContext(site)
00530         context._files['actions.xml'] = _I18N_IMPORT
00531         importActionProviders(context)
00532 
00533         self.assertEqual(len(atool.listActionProviders()), 1)
00534         self.assertEqual(atool.objectIds(), ['dummy'])
00535         self.assertEqual(atool.dummy.objectIds(), ['foo'])
00536         self.assertEqual(atool.dummy.foo.i18n_domain, 'foo_domain')
00537 
00538         # complete the roundtrip
00539         context = DummyExportContext(site)
00540         exportActionProviders(context)
00541 
00542         self.assertEqual(len(context._wrote), 1)
00543         filename, text, content_type = context._wrote[0]
00544         self.assertEqual(filename, 'actions.xml')
00545         self._compareDOM(text, _I18N_IMPORT)
00546         self.assertEqual(content_type, 'text/xml')
00547 
00548     def test_insert_skip_purge(self):
00549         from Products.CMFCore.exportimport.actions \
00550                 import importActionProviders
00551 
00552         site = self._initSite(0, 0)
00553         atool = site.portal_actions
00554 
00555         context = DummyImportContext(site)
00556         context._files['actions.xml'] = _NEWSYTLE_EXPORT
00557         importActionProviders(context)
00558 
00559         self.assertEqual(len(atool.listActionProviders()), 1)
00560         self.assertEqual(atool.objectIds(), ['dummy'])
00561         self.assertEqual(atool.dummy.objectIds(), ['foo', 'bar'])
00562         self.assertEqual(atool.dummy.foo.icon_expr, '')
00563 
00564         context = DummyImportContext(site, False)
00565         context._files['actions.xml'] = _INSERT_IMPORT
00566         importActionProviders(context)
00567 
00568         self.assertEqual(len(atool.listActionProviders()), 1)
00569         self.assertEqual(atool.objectIds(), ['dummy'])
00570         self.assertEqual(atool.dummy.objectIds(), ['spam', 'bar', 'foo'])
00571         self.assertEqual(atool.dummy.foo.icon_expr, 'string:foo_icon.png')
00572 
00573     def test_remove_skip_purge(self):
00574         from Products.CMFCore.exportimport.actions \
00575                 import importActionProviders
00576 
00577         site = self._initSite(2, 2)
00578         atool = site.portal_actions
00579 
00580         self.assertEqual(atool.listActionProviders(),
00581                           ['portal_actions', 'portal_foo', 'portal_bar'])
00582 
00583         context = DummyImportContext(site, False)
00584         context._files['actions.xml'] = _REMOVE_IMPORT
00585         importActionProviders(context)
00586 
00587         self.assertEqual(atool.listActionProviders(), ['portal_foo'])
00588 
00589 
00590 def test_suite():
00591     return unittest.TestSuite((
00592         unittest.makeSuite(ActionNodeAdapterTests),
00593         unittest.makeSuite(ActionCategoryNodeAdapterTests),
00594         unittest.makeSuite(ActionsToolXMLAdapterTests),
00595         unittest.makeSuite(exportActionProvidersTests),
00596         unittest.makeSuite(importActionProvidersTests),
00597         ))
00598 
00599 if __name__ == '__main__':
00600     from Products.CMFCore.testing import run
00601     run(test_suite())