Back to index

plone3  3.1.7
setup.py
Go to the documentation of this file.
00001 #
00002 # PloneTestCase setup
00003 #
00004 
00005 # $Id: setup.py 54876 2007-12-04 16:02:36Z shh42 $
00006 
00007 from Testing import ZopeTestCase
00008 
00009 ZopeTestCase.installProduct('CMFCore')
00010 ZopeTestCase.installProduct('CMFDefault')
00011 ZopeTestCase.installProduct('CMFCalendar')
00012 ZopeTestCase.installProduct('CMFTopic')
00013 ZopeTestCase.installProduct('DCWorkflow')
00014 ZopeTestCase.installProduct('CMFUid', quiet=1)
00015 ZopeTestCase.installProduct('CMFActionIcons')
00016 ZopeTestCase.installProduct('CMFQuickInstallerTool')
00017 ZopeTestCase.installProduct('CMFFormController')
00018 ZopeTestCase.installProduct('GroupUserFolder')
00019 ZopeTestCase.installProduct('ZCTextIndex')
00020 ZopeTestCase.installProduct('CMFPlone')
00021 
00022 # Check for Plone 2.1 or above
00023 try:
00024     from Products.CMFPlone.migrations import v2_1
00025 except ImportError:
00026     PLONE21 = 0
00027 else:
00028     PLONE21 = 1
00029 
00030 # Check for Plone 2.5 or above
00031 try:
00032     from Products.CMFPlone.migrations import v2_5
00033 except ImportError:
00034     PLONE25 = 0
00035 else:
00036     PLONE25 = 1
00037     PLONE21 = 1
00038 
00039 # Check for Plone 3.0 or above
00040 try:
00041     from Products.CMFPlone.migrations import v3_0
00042 except ImportError:
00043     PLONE30 = 0
00044 else:
00045     PLONE30 = 1
00046     PLONE25 = 1
00047     PLONE21 = 1
00048 
00049 # Check for Plone 3.1 or above
00050 try:
00051     from Products.CMFPlone.migrations import v3_1
00052 except ImportError:
00053     PLONE31 = 0
00054 else:
00055     PLONE31 = 1
00056     PLONE30 = 1
00057     PLONE25 = 1
00058     PLONE21 = 1
00059 
00060 # Check for Plone 4.0 or above
00061 try:
00062     from Products.CMFPlone.migrations import v4_0
00063 except ImportError:
00064     PLONE40 = 0
00065 else:
00066     PLONE40 = 1
00067     PLONE31 = 1
00068     PLONE30 = 1
00069     PLONE25 = 1
00070     PLONE21 = 1
00071 
00072 if PLONE21:
00073     ZopeTestCase.installProduct('Archetypes')
00074     ZopeTestCase.installProduct('MimetypesRegistry', quiet=1)
00075     ZopeTestCase.installProduct('PortalTransforms', quiet=1)
00076     ZopeTestCase.installProduct('ATContentTypes')
00077     ZopeTestCase.installProduct('ATReferenceBrowserWidget')
00078     ZopeTestCase.installProduct('CMFDynamicViewFTI')
00079     ZopeTestCase.installProduct('ExternalEditor')
00080     ZopeTestCase.installProduct('ExtendedPathIndex')
00081     ZopeTestCase.installProduct('ResourceRegistries')
00082     ZopeTestCase.installProduct('SecureMailHost')
00083 
00084 if PLONE25:
00085     ZopeTestCase.installProduct('CMFPlacefulWorkflow')
00086     ZopeTestCase.installProduct('PasswordResetTool')
00087     ZopeTestCase.installProduct('PluggableAuthService')
00088     ZopeTestCase.installProduct('PluginRegistry')
00089     ZopeTestCase.installProduct('PlonePAS')
00090     ZopeTestCase.installProduct('kupu')
00091     # In Plone 2.5 we need the monkey-patch applied, starting
00092     # with Plone 3.0 it is part of CMFPlone.patches.
00093     try:
00094         from Products.PlacelessTranslationService import PatchStringIO
00095     except ImportError:
00096         pass
00097 
00098 if PLONE30:
00099     ZopeTestCase.installProduct('CMFEditions')
00100     ZopeTestCase.installProduct('CMFDiffTool')
00101     ZopeTestCase.installProduct('PloneLanguageTool')
00102 
00103 ZopeTestCase.installProduct('MailHost', quiet=1)
00104 ZopeTestCase.installProduct('PageTemplates', quiet=1)
00105 ZopeTestCase.installProduct('PythonScripts', quiet=1)
00106 ZopeTestCase.installProduct('ExternalMethod', quiet=1)
00107 
00108 # Check for layer support
00109 try:
00110     import zope.testing.testrunner
00111 except ImportError:
00112     USELAYER = 0
00113 else:
00114     USELAYER = 1
00115 
00116 # Check for Zope3 interfaces
00117 try:
00118     from zope.interface.interfaces import IInterface
00119 except ImportError:
00120     Z3INTERFACES = 0
00121 else:
00122     from interfaces import IPloneTestCase
00123     Z3INTERFACES = IInterface.providedBy(IPloneTestCase)
00124 
00125 # BBB: Zope 2.8
00126 if PLONE25 and not USELAYER:
00127     ZopeTestCase.installProduct('Five')
00128 
00129 from Testing.ZopeTestCase import transaction
00130 from AccessControl.SecurityManagement import newSecurityManager
00131 from AccessControl.SecurityManagement import noSecurityManager
00132 from Acquisition import aq_base
00133 from time import time
00134 from Globals import PersistentMapping
00135 
00136 if PLONE21:
00137     from Products.CMFPlone.utils import _createObjectByType
00138 else:
00139     from Products.CMFPlone.PloneUtilities import _createObjectByType
00140 
00141 portal_name = 'plone'
00142 portal_owner = 'portal_owner'
00143 default_policy = 'Default Plone'
00144 default_products = ()
00145 default_user = ZopeTestCase.user_name
00146 default_password = ZopeTestCase.user_password
00147 
00148 default_base_profile = 'CMFPlone:plone'
00149 default_extension_profiles = ()
00150 
00151 if PLONE30:
00152     default_base_profile = 'Products.CMFPlone:plone'
00153 
00154 
00155 def setupPloneSite(id=portal_name,
00156                    policy=default_policy,
00157                    products=default_products,
00158                    quiet=0,
00159                    with_default_memberarea=1,
00160                    base_profile=default_base_profile,
00161                    extension_profiles=default_extension_profiles):
00162     '''Creates a Plone site and/or quickinstalls products into it.'''
00163     if USELAYER:
00164         quiet = 1
00165         cleanupPloneSite(id)
00166     SiteSetup(id, policy, products, quiet, with_default_memberarea,
00167               base_profile, extension_profiles).run()
00168 
00169 if USELAYER:
00170     import layer
00171     setupPloneSite = layer.onsetup(setupPloneSite)
00172 
00173 
00174 def cleanupPloneSite(id):
00175     '''Removes a site.'''
00176     SiteCleanup(id).run()
00177 
00178 if USELAYER:
00179     import layer
00180     cleanupPloneSite = layer.onteardown(cleanupPloneSite)
00181 
00182 
00183 class SiteSetup:
00184     '''Creates a Plone site and/or quickinstalls products into it.'''
00185 
00186     def __init__(self, id, policy, products, quiet, with_default_memberarea,
00187                  base_profile, extension_profiles):
00188         self.id = id
00189         self.policy = policy
00190         self.products = products
00191         self.quiet = quiet
00192         self.with_default_memberarea = with_default_memberarea
00193         self.base_profile = base_profile
00194         self.extension_profiles = tuple(extension_profiles)
00195 
00196     def run(self):
00197         self.app = self._app()
00198         try:
00199             uf = self.app.acl_users
00200             if uf.getUserById(portal_owner) is None:
00201                 # Add portal owner
00202                 uf.userFolderAddUser(portal_owner, default_password, ['Manager'], [])
00203             if not hasattr(aq_base(self.app), self.id):
00204                 # Add site
00205                 self._login(uf, portal_owner)
00206                 self._optimize()
00207                 self._setupPloneSite()
00208                 self._setupRegistries()
00209             if hasattr(aq_base(self.app), self.id):
00210                 # Configure site
00211                 self._login(uf, portal_owner)
00212                 self._placefulSetUp()
00213                 self._setupProfiles()
00214                 self._setupProducts()
00215         finally:
00216             self._abort()
00217             self._placefulTearDown()
00218             self._close()
00219             self._logout()
00220 
00221     def _setupPloneSite(self):
00222         '''Creates the Plone site.'''
00223         if PLONE30:
00224             self._setupCreatedHook()
00225         if PLONE25:
00226             self._setupPloneSite_with_genericsetup()
00227         else:
00228             self._setupPloneSite_with_portalgenerator()
00229 
00230     def _setupPloneSite_with_genericsetup(self):
00231         '''Creates the site using GenericSetup.'''
00232         start = time()
00233         if self.base_profile != default_base_profile:
00234             self._print('Adding Plone Site (%s) ... ' % (self.base_profile,))
00235         else:
00236             self._print('Adding Plone Site ... ')
00237         # Add Plone site
00238         factory = self.app.manage_addProduct['CMFPlone']
00239         factory.addPloneSite(self.id, create_userfolder=1, snapshot=0,
00240                              profile_id=self.base_profile)
00241         # Pre-create default memberarea to speed up the tests
00242         if self.with_default_memberarea:
00243             self._setupHomeFolder()
00244         self._commit()
00245         self._print('done (%.3fs)\n' % (time()-start,))
00246 
00247     def _setupPloneSite_with_portalgenerator(self):
00248         '''Creates the site using PortalGenerator.'''
00249         start = time()
00250         if self.policy != default_policy:
00251             self._print('Adding Plone Site (%s) ... ' % (self.policy,))
00252         else:
00253             self._print('Adding Plone Site ... ')
00254         # Add Plone site
00255         factory = self.app.manage_addProduct['CMFPlone']
00256         factory.manage_addSite(self.id, create_userfolder=1, custom_policy=self.policy)
00257         # Pre-create default memberarea to speed up the tests
00258         if self.with_default_memberarea:
00259             self._setupHomeFolder()
00260         self._commit()
00261         self._print('done (%.3fs)\n' % (time()-start,))
00262 
00263     def _setupRegistries(self):
00264         '''Installs persistent registries.'''
00265         portal = getattr(self.app, self.id)
00266         if not hasattr(portal, '_installed_profiles'):
00267             portal._installed_profiles = PersistentMapping()
00268             self._commit()
00269 
00270     def _setupProfiles(self):
00271         '''Imports extension profiles into the site.'''
00272         portal = getattr(self.app, self.id)
00273         setup = getattr(portal, 'portal_setup', None)
00274         if setup is not None:
00275             for profile in self.extension_profiles:
00276                 if not portal._installed_profiles.has_key(profile):
00277                     start = time()
00278                     self._print('Adding %s ... ' % (profile,))
00279                     profile_id = 'profile-%s' % (profile,)
00280                     if PLONE30:
00281                         setup.runAllImportStepsFromProfile(profile_id)
00282                     else:
00283                         saved = setup.getImportContextID()
00284                         try:
00285                             setup.setImportContext(profile_id)
00286                             setup.runAllImportSteps()
00287                         finally:
00288                             setup.setImportContext(saved)
00289                     portal._installed_profiles[profile] = 1
00290                     self._commit()
00291                     self._print('done (%.3fs)\n' % (time()-start,))
00292 
00293     def _setupProducts(self):
00294         '''Quickinstalls products into the site.'''
00295         portal = getattr(self.app, self.id)
00296         qi = portal.portal_quickinstaller
00297         for product in self.products:
00298             if not qi.isProductInstalled(product):
00299                 if qi.isProductInstallable(product):
00300                     start = time()
00301                     self._print('Adding %s ... ' % (product,))
00302                     qi.installProduct(product)
00303                     self._commit()
00304                     self._print('done (%.3fs)\n' % (time()-start,))
00305                 else:
00306                     self._print('Adding %s ... NOT INSTALLABLE\n' % (product,))
00307 
00308     def _setupHomeFolder(self):
00309         '''Creates the default user's member folder.'''
00310         portal = getattr(self.app, self.id)
00311         _createHomeFolder(portal, default_user, take_ownership=0)
00312 
00313     def _setupCreatedHook(self):
00314         '''Registers a handler for ISiteManagerCreatedEvent.'''
00315         from zope.component import getGlobalSiteManager
00316         from Products.CMFPlone.interfaces import ISiteManagerCreatedEvent
00317         gsm = getGlobalSiteManager()
00318         gsm.registerHandler(_placefulSetUpHandler, (ISiteManagerCreatedEvent,))
00319 
00320     def _placefulSetUp(self):
00321         '''Sets the local site/manager.'''
00322         if PLONE30:
00323             portal = getattr(self.app, self.id)
00324             _placefulSetUp(portal)
00325 
00326     def _placefulTearDown(self):
00327         '''Resets the local site/manager.'''
00328         if PLONE30:
00329             _placefulTearDown()
00330 
00331     def _optimize(self):
00332         '''Applies optimizations to the PortalGenerator.'''
00333         _optimize()
00334 
00335     def _app(self):
00336         '''Opens a ZODB connection and returns the app object.'''
00337         return ZopeTestCase.app()
00338 
00339     def _close(self):
00340         '''Closes the ZODB connection.'''
00341         ZopeTestCase.close(self.app)
00342 
00343     def _login(self, uf, name):
00344         '''Logs in as user 'name' from user folder 'uf'.'''
00345         user = uf.getUserById(name).__of__(uf)
00346         newSecurityManager(None, user)
00347 
00348     def _logout(self):
00349         '''Logs out.'''
00350         noSecurityManager()
00351 
00352     def _commit(self):
00353         '''Commits the transaction.'''
00354         transaction.commit()
00355 
00356     def _abort(self):
00357         '''Aborts the transaction.'''
00358         transaction.abort()
00359 
00360     def _print(self, msg):
00361         '''Prints msg to stderr.'''
00362         if not self.quiet:
00363             ZopeTestCase._print(msg)
00364 
00365 
00366 class SiteCleanup(SiteSetup):
00367     '''Removes a site.'''
00368 
00369     def __init__(self, id):
00370         self.id = id
00371 
00372     def run(self):
00373         self.app = self._app()
00374         try:
00375             if hasattr(aq_base(self.app), self.id):
00376                 self._placefulSetUp()
00377                 self.app._delObject(self.id)
00378                 self._commit()
00379         finally:
00380             self._abort()
00381             self._close()
00382             self._placefulTearDown()
00383 
00384 
00385 def _placefulSetUpHandler(event):
00386     '''Subscriber for ISiteManagerCreatedEvent.
00387        Sets the local site/manager.
00388     '''
00389     portal = event.object
00390     _placefulSetUp(portal)
00391 
00392 
00393 def _placefulSetUp(portal):
00394     '''Sets the local site/manager.'''
00395     from zope.app.component.hooks import setHooks, setSite
00396     setHooks()
00397     setSite(portal)
00398 
00399 
00400 def _placefulTearDown():
00401     '''Resets the local site/manager.'''
00402     from zope.app.component.hooks import resetHooks, setSite
00403     resetHooks()
00404     setSite()
00405 
00406 
00407 def _createHomeFolder(portal, member_id, take_ownership=1):
00408     '''Creates a memberarea if it does not already exist.'''
00409     pm = portal.portal_membership
00410     members = pm.getMembersFolder()
00411 
00412     if not hasattr(aq_base(members), member_id):
00413         # Create home folder
00414         _createObjectByType('Folder', members, id=member_id)
00415         if not PLONE21:
00416             # Create personal folder
00417             home = pm.getHomeFolder(member_id)
00418             _createObjectByType('Folder', home, id=pm.personal_id)
00419             # Uncatalog personal folder
00420             personal = pm.getPersonalFolder(member_id)
00421             personal.unindexObject()
00422 
00423     if take_ownership:
00424         user = portal.acl_users.getUserById(member_id)
00425         if user is None:
00426             raise ValueError, 'Member %s does not exist' % member_id
00427         if not hasattr(user, 'aq_base'):
00428             user = user.__of__(portal.acl_users)
00429         # Take ownership of home folder
00430         home = pm.getHomeFolder(member_id)
00431         home.changeOwnership(user)
00432         home.__ac_local_roles__ = None
00433         home.manage_setLocalRoles(member_id, ['Owner'])
00434         if not PLONE21:
00435             # Take ownership of personal folder
00436             personal = pm.getPersonalFolder(member_id)
00437             personal.changeOwnership(user)
00438             personal.__ac_local_roles__ = None
00439             personal.manage_setLocalRoles(member_id, ['Owner'])
00440 
00441 
00442 def _optimize():
00443     '''Significantly reduces portal creation time.'''
00444     # Don't compile expressions on creation
00445     def __init__(self, text):
00446         self.text = text
00447     from Products.CMFCore.Expression import Expression
00448     Expression.__init__ = __init__
00449     # Don't clone actions but convert to list only
00450     def _cloneActions(self):
00451         return list(self._actions)
00452     from Products.CMFCore.ActionProviderBase import ActionProviderBase
00453     ActionProviderBase._cloneActions = _cloneActions
00454     # The site creation code is not needed anymore in Plone >= 2.5
00455     # as it is now based on GenericSetup
00456     if not PLONE25:
00457         # Don't setup default directory views
00458         def setupDefaultSkins(self, p):
00459             from Products.CMFCore.utils import getToolByName
00460             ps = getToolByName(p, 'portal_skins')
00461             ps.manage_addFolder(id='custom')
00462             ps.addSkinSelection('Basic', 'custom')
00463         from Products.CMFPlone.Portal import PloneGenerator
00464         PloneGenerator.setupDefaultSkins = setupDefaultSkins
00465         # Don't setup default Members folder
00466         def setupMembersFolder(self, p):
00467             pass
00468         PloneGenerator.setupMembersFolder = setupMembersFolder
00469         # Don't setup Plone content (besides Members folder)
00470         def setupPortalContent(self, p):
00471             _createObjectByType('Large Plone Folder', p, id='Members', title='Members')
00472             if not PLONE21:
00473                 p.Members.unindexObject()
00474         PloneGenerator.setupPortalContent = setupPortalContent
00475     # Don't populate type fields in the ConstrainTypesMixin schema
00476     if PLONE21:
00477         def _ct_defaultAddableTypeIds(self):
00478             return []
00479         from Products.ATContentTypes.lib.constraintypes import ConstrainTypesMixin
00480         ConstrainTypesMixin._ct_defaultAddableTypeIds = _ct_defaultAddableTypeIds
00481