From: Martin A. <svn...@pl...> - 2010-05-24 16:58:34
|
Author: optilude Date: Mon May 24 16:58:26 2010 New Revision: 36727 Modified: plone.app.testing/trunk/plone/app/testing/__init__.py plone.app.testing/trunk/plone/app/testing/cleanup.py plone.app.testing/trunk/plone/app/testing/cleanup.txt plone.app.testing/trunk/plone/app/testing/helpers.py plone.app.testing/trunk/plone/app/testing/helpers.txt plone.app.testing/trunk/plone/app/testing/layers.py plone.app.testing/trunk/plone/app/testing/tests.py Log: Fix cleanup functions for GenericSetup. Test helpers. Fix __bases__ unpickling chicken and egg issue with the local site manager. Add layer base class for managing sandboxed ZODB/ZCA setups. Modified: plone.app.testing/trunk/plone/app/testing/__init__.py ============================================================================== --- plone.app.testing/trunk/plone/app/testing/__init__.py (original) +++ plone.app.testing/trunk/plone/app/testing/__init__.py Mon May 24 16:58:26 2010 @@ -4,7 +4,7 @@ PLONE_INTEGRATION_TESTING, PLONE_FUNCTIONAL_TESTING, PLONE_ZSERVER, - PLONE_FTP_SERVER + PLONE_FTP_SERVER, ) # Helper functions @@ -14,7 +14,7 @@ setRoles, quickInstallProduct, - installProfile, + applyProfile, pushGlobalRegistry, popGlobalRegistry, @@ -22,7 +22,9 @@ tearDownProfileRegistation, tearDownMultiPluginRegistration, - ploneSite + ploneSite, + + PloneSandboxLayer ) # Constants @@ -38,3 +40,9 @@ SITE_OWNER_USER_NAME, SITE_OWNER_USER_PASSWORD ) + +# Cleanup handlers +from plone.app.testing.cleanup import ( + cleanUpGenericSetupRegistries, + cleanUpMultiPlugins, + ) Modified: plone.app.testing/trunk/plone/app/testing/cleanup.py ============================================================================== --- plone.app.testing/trunk/plone/app/testing/cleanup.py (original) +++ plone.app.testing/trunk/plone/app/testing/cleanup.py Mon May 24 16:58:26 2010 @@ -3,15 +3,23 @@ from zope.testing.cleanup import addCleanUp -def cleanUpProfileRegistry(): +# Make sure cleanup handlers from GenericSetup are registered +try: + import Products.GenericSetup.zcml +except ImportError: + pass + +def cleanUpGenericSetupRegistries(): try: - from Products.GenericSetup.registry import _profile_registry + from Products.GenericSetup import registry except ImportError: pass else: - _profile_registry.clear() + registry._import_step_registry.clear() + registry._export_step_registry.clear() + registry._profile_registry.clear() -addCleanUp(cleanUpProfileRegistry) +addCleanUp(cleanUpGenericSetupRegistries) def cleanUpMultiPlugins(): try: @@ -22,3 +30,4 @@ del MultiPlugins[:] addCleanUp(cleanUpMultiPlugins) +del addCleanUp \ No newline at end of file Modified: plone.app.testing/trunk/plone/app/testing/cleanup.txt ============================================================================== --- plone.app.testing/trunk/plone/app/testing/cleanup.txt (original) +++ plone.app.testing/trunk/plone/app/testing/cleanup.txt Mon May 24 16:58:26 2010 @@ -12,23 +12,36 @@ The profiles registry is populated on startup via the ``registerProfile()`` or the corresponding ``<genericsetup:registerProfile />`` ZCML directive. +Similarly, there are registries for import and export steps. >>> from Products.GenericSetup.registry import _profile_registry + >>> from Products.GenericSetup.registry import _import_step_registry + >>> from Products.GenericSetup.registry import _export_step_registry -A dummy profile may look like so: +A dummy profile and import/export steps may be registered like so: - >>> _profile_registry.registerProfile('dummy', u"Dummy profile", u"", ".", 'plone.app.testing') - -We can find it in the profile registry again: - - >>> _profile_registry.listProfiles() - ('plone.app.testing:dummy',) + >>> _profile_registry.registerProfile('dummy1', u"Dummy profile", u"", ".", 'plone.app.testing') + >>> _import_step_registry.registerStep('dummy2', version=1, handler='plone.app.testing.tests.dummy', title=u"Dummy import step", description=u"") + >>> _export_step_registry.registerStep('dummy3', handler='plone.app.testing.tests.dummy', title=u"Dummy import step", description=u"") + +The registries now contain these items: + + >>> tuple(_profile_registry.listProfiles()) + ('plone.app.testing:dummy1',) + >>> tuple(_import_step_registry.listSteps()) + ('dummy2',) + >>> tuple(_export_step_registry.listSteps()) + ('dummy3',) -On cleanup, the registry is cleared. +On cleanup, the registries are cleared. >>> zope.testing.cleanup.cleanUp() - >>> _profile_registry.listProfiles() + >>> tuple(_profile_registry.listProfiles()) + () + >>> tuple(_import_step_registry.listSteps()) + () + >>> tuple(_export_step_registry.listSteps()) () PluggableAuthService MultiPlugins list Modified: plone.app.testing/trunk/plone/app/testing/helpers.py ============================================================================== --- plone.app.testing/trunk/plone/app/testing/helpers.py (original) +++ plone.app.testing/trunk/plone/app/testing/helpers.py Mon May 24 16:58:26 2010 @@ -3,8 +3,9 @@ import contextlib -from plone.testing import z2, zca +from plone.testing import z2, zodb, zca, Layer +from plone.app.testing import layers from plone.app.testing.interfaces import ( PLONE_SITE_ID, SITE_OWNER_USER_NAME @@ -80,10 +81,14 @@ is installed already. """ - from AccessControl import getSecurityManager, setSecurityManager + from Acquisition import aq_parent + from AccessControl import getSecurityManager + from AccessControl.SecurityManagement import setSecurityManager + sm = getSecurityManager() + app = aq_parent(portal) - login(portal, SITE_OWNER_USER_NAME) + z2.login(app['acl_users'], SITE_OWNER_USER_NAME) try: quickinstaller = portal['portal_quickinstaller'] @@ -100,15 +105,19 @@ finally: setSecurityManager(sm) -def installProfile(portal, profileName): +def applyProfile(portal, profileName): """Install an extension profile into the portal. The profile name should be a package name and a profile name, e.g. 'my.product:default'. """ - from AccessControl import getSecurityManager, setSecurityManager + from Acquisition import aq_parent + from AccessControl import getSecurityManager + from AccessControl.SecurityManagement import setSecurityManager + sm = getSecurityManager() + app = aq_parent(portal) - login(portal, SITE_OWNER_USER_NAME) + z2.login(app['acl_users'], SITE_OWNER_USER_NAME) try: setupTool = portal['portal_setup'] @@ -137,13 +146,17 @@ new global registry as its base. """ + from zope.site.hooks import setSite, getSite, setHooks + site = getSite() + current = zca.pushGlobalRegistry(new=new) - from five.localsitemanager import update_sitemanager_bases - update_sitemanager_bases(portal) + if site is not None: + setHooks() + setSite(site) return current - + def popGlobalRegistry(portal): """Restore the global component registry form the top of the stack, as set with ``pushGlobalRegistry()``. @@ -152,10 +165,40 @@ new global registry as its base. """ + # First, check if the component site has the global site manager in its + # bases. If so, that site manager is about to disappear, so set its + # base(s) as the new base(s) for the local site manager. + + from zope.component import getGlobalSiteManager + globalSiteManager = getGlobalSiteManager() + + gsmBases = globalSiteManager.__bases__ + + from zope.site.hooks import setSite, getSite, setHooks + site = getSite() + + localSiteManager = portal.getSiteManager() + + bases = [] + changed = False + for base in localSiteManager.__bases__: + if base is globalSiteManager: + bases.extend(gsmBases) + changed = True + else: + bases.append(base) + + if changed: + localSiteManager.__bases__ = tuple(bases) + + # Now pop the registry. We need to do it in this somewhat convoluted way + # to avoid the risk of unpickling errors + previous = zca.popGlobalRegistry() - from five.localsitemanager import update_sitemanager_bases - update_sitemanager_bases(portal) + if site is not None: + setHooks() + setSite(site) return previous @@ -177,5 +220,91 @@ closed). """ + from zope.site.hooks import setSite, getSite, setHooks + setHooks() + + site = getSite() + with z2.zopeApp(db, connection, environ) as app: - yield app[PLONE_SITE_ID] + portal = app[PLONE_SITE_ID] + + setSite(portal) + + try: + yield portal + finally: + if site is not portal: + setSite(site) + +# Layer base class + +class PloneSandboxLayer(Layer): + """Layer base class managing the common pattern of having a stacked ZODB + ``DemoStorage`` and a stacked global component registry for the layer. + + Base classes must override and implemented ``setUpPloneSite()``. They + may also implement ``tearDownPloneSite()``, and can optionally change + the ``defaultBases`` tuple. + """ + + # The default list of bases. Consider setting to PLONE_FUNCTIONAL_TESTING + # for functional testing. + + defaultBases = (layers.PLONE_INTEGRATION_TESTING,) + + # Hooks + + def setUpPloneSite(self, portal): + """Set up the Plone site. + + ``portal`` is the Plone site. Provided no exception is raised, changes + to this site will be committed (into a newly stacked ``DemoStorage``). + + Concrete layer classes should implement this method at a minimum. + """ + + raise NotImplementedError("The setUpPloneSite() must be implemented by a concrete layer") + + def tearDownPloneSite(self, portal): + """Tear down the Plone site. + + Implementing this is optional. If the changes made during the + ``setUpPloneSite()`` method were confined to the ZODB and the global + component regsitry, those changes will be torn down automatically. + """ + + pass + + # Boilerplate + + def setUp(self): + + # Push a new database storage so that database changes + # commited during layer setup can be easily torn down + self['zodbDB'] = zodb.stackDemoStorage(self.get('zodbDB'), name='HelperDemos') + + with ploneSite() as portal: + + # Push a new component registry so that ZCML registations + # and other global component registry changes are sandboxed + pushGlobalRegistry(portal) + + # Call template method - must be implemented by subclasses + self.setUpPloneSite(portal) + + def tearDown(self): + + with ploneSite() as portal: + + # Call template method - may be implemented by subclasses + self.tearDownPloneSite(portal) + + # Pop the component registry, thus removing component + # architecture registrations + popGlobalRegistry(portal) + + # Pop the demo storage, thus restoring the database to the + # previous state + self['zodbDB'].close() + del self['zodbDB'] + Modified: plone.app.testing/trunk/plone/app/testing/helpers.txt ============================================================================== --- plone.app.testing/trunk/plone/app/testing/helpers.txt (original) +++ plone.app.testing/trunk/plone/app/testing/helpers.txt Mon May 24 16:58:26 2010 @@ -1,9 +1,12 @@ Plone testing helpers --------------------- +--------------------- -This package contains various test helpers. They are all importable from -``plone.app.testing`` directly, or from their canonical locations at -``plone.app.testing.helpers``. +This package contains various test helpers that are useful for writing custom +layers using the ``PloneSite`` fixture, and for writing tests using such +layers. + +The helpers are all importable from ``plone.app.testing`` directly, or from +their canonical locations at ``plone.app.testing.helpers``. >>> from plone.app.testing import helpers @@ -11,11 +14,354 @@ >>> from zope.testing.testrunner import runner -User management ---------------- +Let's create a custom layer that exercises these helpers. In this layer, we +will perform the following setup: + +1. Stack a new ``DemoStorage`` on top of the one from the base layer. This + ensures that any persistent changes performed in this layer can be torn + down completely, simply by popping the demo storage. + +2. Push a new global component registry. This allows us to register components + (e.g. by loading ZCML or using the test API from ``zope.component``) and + tear down those registration easily by popping the component registry. + We pass the portal so that the local component site manager can be + configured appropriately. + + *Note:* We obtain the portal from the ``ploneSite()`` context manager, + which will ensure that the portal is properly set up and commit our changes + on exiting the ``with`` block. + +3. Make some persistent changes, to illustrate how these are torn down when + we pop the ZODB ``DemoStorage``. + +4. Install a product using the ``portal_quickinstaller`` tool. + +5. Apply a named extension profile. + +On tear-down, we only need to pop the ``DemoStorage`` (to roll back all +persistent changes) and the stacked component registry (to roll back all +global component registrations). Of course, if our setup had changed any other +global or external state, we would need to tear that down as well. + + >>> from plone.testing import Layer + >>> from plone.testing import zca, z2, zodb + + >>> from plone.app.testing import PLONE_INTEGRATION_TESTING + + >>> class HelperDemos(Layer): + ... defaultBases = (PLONE_INTEGRATION_TESTING,) + ... + ... def setUp(self): + ... + ... # Push a new database storage so that database changes + ... # commited during layer setup can be easily torn down + ... self['zodbDB'] = zodb.stackDemoStorage(self.get('zodbDB'), name='HelperDemos') + ... + ... with helpers.ploneSite() as portal: + ... + ... # Push a new component registry so that ZCML registations + ... # and other global component registry changes are sandboxed + ... helpers.pushGlobalRegistry(portal) + ... + ... # Register some components + ... from zope.component import provideUtility + ... from zope.interface import Interface + ... provideUtility(object(), Interface, name=u"dummy1") + ... + ... # Make some persistent changes + ... portal.title = u"New title" + ... + ... # Install a product using portal_quickinstaller + ... helpers.quickInstallProduct(portal, 'plonetheme.classic') + ... + ... # Apply a GenericSetup (extension) profile + ... helpers.applyProfile(portal, 'plonetheme.sunburst:default') + ... + ... def tearDown(self): + ... + ... # Pop the component registry, thus removing component + ... # architecture registrations + ... with helpers.ploneSite() as portal: + ... helpers.popGlobalRegistry(portal) + ... + ... # Pop the demo storage, thus restoring the database to the + ... # previous state + ... self['zodbDB'].close() + ... del self['zodbDB'] + + >>> HELPER_DEMOS = HelperDemos() + +Let's now simulate layer setup: + + >>> options = runner.get_options([], []) + >>> setupLayers = {} + >>> runner.setup_layer(options, HELPER_DEMOS, setupLayers) + Set up plone.testing.zca.LayerCleanup in ... seconds. + Set up plone.testing.z2.Startup in ... seconds. + Set up plone.testing.z2.IntegrationTesting in ... seconds. + Set up plone.app.testing.layers.PloneSite:Integration in ... seconds. + Set up HelperDemos in ... seconds. + +We should see the newly registered components and the persistent changes +having taken effect. + + >>> from zope.component import queryUtility + >>> from zope.interface import Interface + >>> queryUtility(Interface, name="dummy1") + <object object at ...> + + >>> with helpers.ploneSite() as portal: + ... print portal.title + New title + +We should also see our product installation in the quickinstaller tool +and the results of the profile having been applied. + + >>> with helpers.ploneSite() as portal: + ... print portal['portal_quickinstaller'].isProductInstalled('plonetheme.classic') + ... print portal['portal_skins'].getDefaultSkin() + True + Sunburst Theme + +Let's now simulate a test. + + >>> zca.LAYER_CLEANUP.testSetUp() + >>> z2.STARTUP.testSetUp() + >>> z2.INTEGRATION_TESTING.testSetUp() + >>> PLONE_INTEGRATION_TESTING.testSetUp() + >>> HELPER_DEMOS.testSetUp() + +In a test, we can use helpers to simulate login, logging out and changing a +user's roles. These may also be used during layer setup if required, using +the ``ploneSite()`` context manager as shown above. + + >>> from AccessControl import getSecurityManager + >>> from plone.app.testing import TEST_USER_NAME + + >>> portal = HELPER_DEMOS['portal'] # would normally be self.layer['portal'] + + >>> getSecurityManager().getUser().getRolesInContext(portal) + ['Member', 'Authenticated'] + + >>> getSecurityManager().getUser().getUserName() == TEST_USER_NAME + True + >>> helpers.setRoles(portal, TEST_USER_NAME, ['Manager']) + >>> getSecurityManager().getUser().getRolesInContext(portal) + ['Manager', 'Authenticated'] + + >>> helpers.logout() + >>> getSecurityManager().getUser() + <SpecialUser 'Anonymous User'> + + >>> helpers.login(portal, TEST_USER_NAME) + >>> getSecurityManager().getUser().getUserName() == TEST_USER_NAME + True + + >>> portal.invokeFactory('Folder', 'folder1', title=u"Folder 1") + 'folder1' + +Let's now tear down the test. + + >>> HELPER_DEMOS.testTearDown() + >>> PLONE_INTEGRATION_TESTING.testTearDown() + >>> z2.INTEGRATION_TESTING.testTearDown() + >>> z2.STARTUP.testTearDown() + >>> zca.LAYER_CLEANUP.testTearDown() + +Our persistent changes from the layer should remain, but those made in a test +should not. + + >>> queryUtility(Interface, name="dummy1") + <object object at ...> + + >>> with helpers.ploneSite() as portal: + ... print portal.title + ... print portal['portal_quickinstaller'].isProductInstalled('plonetheme.classic') + ... print portal['portal_skins'].getDefaultSkin() + ... 'folder1' in portal.objectIds() + New title + True + Sunburst Theme + False + +We'll now tear down just the HELPER_DEMOS layer. At this point, we should +still have a Plone site, but none of the persistent or component architecture +changes from our layer. + + >>> runner.tear_down_unneeded(options, [l for l in setupLayers if l is not HELPER_DEMOS], setupLayers) + Tear down HelperDemos in ... seconds. + + >>> queryUtility(Interface, name="dummy1") is None + True + + >>> with helpers.ploneSite() as portal: + ... print portal.title + ... print portal['portal_quickinstaller'].isProductInstalled('plonetheme.classic') + ... print portal['portal_skins'].getDefaultSkin() + Plone + False + Sunburst Theme + +Let's tear down the rest of the layers too. + + >>> runner.tear_down_unneeded(options, [], setupLayers) + Tear down plone.app.testing.layers.PloneSite:Integration in ... seconds. + Tear down plone.testing.z2.IntegrationTesting in ... seconds. + Tear down plone.testing.z2.Startup in ... seconds. + Tear down plone.testing.zca.LayerCleanup in ... seconds. + +Plone sandbox layer helper +-------------------------- + +The pattern above of setting up a stacked ZODB ``DemoStorage`` and a stacked +global component registry is very common. In fact, there is a layer base +class which helps implement this pattern. + + >>> someGlobal = {} + + >>> class MyLayer(helpers.PloneSandboxLayer): + ... + ... def setUpPloneSite(self, portal): + ... + ... # Register some components + ... from zope.component import provideUtility + ... from zope.interface import Interface + ... provideUtility(object(), Interface, name=u"dummy1") + ... + ... # Make some persistent changes + ... portal.title = u"New title" + ... + ... # Make some other global changes not stored in the ZODB or + ... # the global component registry + ... someGlobal['test'] = 1 + ... + ... def tearDownPloneSite(self, portal): + ... # Illustrate tear-down of some global state + ... del someGlobal['test'] + + >>> MY_LAYER = MyLayer() + +Here, we have derived from ``PloneSandboxLayer`` instead of the more usual +``Layer`` base class. This layer implements the sandboxing for us, and +delegates to two template methods: ``setUpPloneSite()`` and +``tearDownPloneSite()``. Both take a configured ``portal`` object as an +argument, giving access to the Plone site root. + +You *must* implement ``setUpPloneSite()``. Implementing +``tearDownPloneSite()`` is optional. If all the state modified during layer +setup is saved in the ZODB and/or the global component registry only, the +standard tear-down will suffice. Other state must be cleaned up explicitly. + +You may also wish to change the ``defaultBases`` argument. The default is to +use ``PLONE_INTEGRATION_TESTING`` as the single default base layer. + + >>> MY_LAYER.__bases__ + (<Layer 'plone.app.testing.layers.PloneSite:Integration'>,) + +Let's now simulate layer setup: + + >>> options = runner.get_options([], []) + >>> setupLayers = {} + >>> runner.setup_layer(options, MY_LAYER, setupLayers) + Set up plone.testing.zca.LayerCleanup in ... seconds. + Set up plone.testing.z2.Startup in ... seconds. + Set up plone.testing.z2.IntegrationTesting in ... seconds. + Set up plone.app.testing.layers.PloneSite:Integration in ... seconds. + Set up MyLayer in ... seconds. + +Again, our state should now be available. + + >>> queryUtility(Interface, name="dummy1") + <object object at ...> + + >>> with helpers.ploneSite() as portal: + ... print portal.title + New title + + >>> someGlobal['test'] + 1 + +We'll now tear down just the MY_LAYER layer. At this point, we should +still have a Plone site, but none of the changes from our layer. + + >>> runner.tear_down_unneeded(options, [l for l in setupLayers if l is not MY_LAYER], setupLayers) + Tear down MyLayer in ... seconds. + + >>> queryUtility(Interface, name="dummy1") is None + True + + >>> with helpers.ploneSite() as portal: + ... print portal.title + Plone + + >>> 'test' in someGlobal + False + +Let's tear down the rest of the layers too. + + >>> runner.tear_down_unneeded(options, [], setupLayers) + Tear down plone.app.testing.layers.PloneSite:Integration in ... seconds. + Tear down plone.testing.z2.IntegrationTesting in ... seconds. + Tear down plone.testing.z2.Startup in ... seconds. + Tear down plone.testing.zca.LayerCleanup in ... seconds. + +Other helpers +------------- + +There are some further helpers that apply only to special cases. + +Many packages will add a new GenericSetup profile to the global profile +registry. The most common way is via the ``<genericsetup:registerProfile />`` +directive, although a call to the ``registerProfile()`` function will achieve +the same thing. + +If your layer loads a package (or the ZCML for a package) that registers such +profiles, you must clean them up again, or you'll risk getting errors if the +package is installed again in another layer. The helper +``tearDownProfileRegistation()`` can be used for this purpose. + +Let's simulate setting up a profile in the registry and then tearing it down. + + >>> from Products.GenericSetup.registry import _profile_registry + >>> _profile_registry.registerProfile('dummy1', u"Dummy profile", u"", ".", 'plone.app.testing') + >>> _profile_registry.registerProfile('dummy2', u"Dummy profile", u"", ".", 'plone.app.testing') + >>> _profile_registry.registerProfile('dummy1', u"Dummy profile", u"", ".", 'plone.testing') + + >>> tuple(_profile_registry.listProfiles()) + ('plone.app.testing:dummy1', 'plone.app.testing:dummy2', 'plone.testing:dummy1') + +The tear down helper takes the product name as an argument and tears down all +profiles for that product (only): + + >>> helpers.tearDownProfileRegistation('plone.app.testing') + >>> tuple(_profile_registry.listProfiles()) + ('plone.testing:dummy1',) + +Let's clean up the registry completely. + + >>> _profile_registry.clear() + +Similarly, a product that uses the ``<pas:registerMultiPlugin />`` or the +``registerMultiPlugin()`` API from ``PluggableAuthService`` may leave global +state that needs to be cleaned up. You can use the helper +``tearDownMultiPluginRegistration()`` for this purpose. + +Let's simulate registering some plugins: + + >>> from Products.PluggableAuthService import PluggableAuthService + >>> PluggableAuthService.registerMultiPlugin("dummy_plugin1") + >>> PluggableAuthService.registerMultiPlugin("dummy_plugin2") + + >>> PluggableAuthService.MultiPlugins + ['dummy_plugin1', 'dummy_plugin2'] + +The tear down helper takes a plugin meta-type as an argument: + + >>> helpers.tearDownMultiPluginRegistration('dummy_plugin1') -Product and profile installation --------------------------------- + >>> PluggableAuthService.MultiPlugins + ['dummy_plugin2'] -Component architecture sandboxing ---------------------------------- +Let's clean up the registry completely. + + >>> del PluggableAuthService.MultiPlugins[:] Modified: plone.app.testing/trunk/plone/app/testing/layers.py ============================================================================== --- plone.app.testing/trunk/plone/app/testing/layers.py (original) +++ plone.app.testing/trunk/plone/app/testing/layers.py Mon May 24 16:58:26 2010 @@ -2,9 +2,7 @@ # plone.app.testing directly from plone.testing import Layer -from plone.testing import z2 -from plone.testing import zca -from plone.testing import zodb +from plone.testing import zodb, zca, z2 from plone.app.testing.interfaces import ( PLONE_SITE_ID, @@ -19,8 +17,6 @@ SITE_OWNER_USER_PASSWORD ) -from plone.app.testing import helpers - class PloneSite(Layer): """This layer sets up a basic Plone site, with: @@ -286,6 +282,7 @@ portal.setupCurrentSkin(portal.REQUEST) # Pseudo-login as the test user + from plone.app.testing import helpers helpers.login(portal, TEST_USER_NAME) def tearDownEnvironment(self, portal): @@ -294,6 +291,7 @@ """ # Clear the security manager + from plone.app.testing import helpers helpers.logout() # Clear any cached data using plone.memoize's RAM caches Modified: plone.app.testing/trunk/plone/app/testing/tests.py ============================================================================== --- plone.app.testing/trunk/plone/app/testing/tests.py (original) +++ plone.app.testing/trunk/plone/app/testing/tests.py Mon May 24 16:58:26 2010 @@ -1,18 +1,17 @@ import unittest2 as unittest import doctest -from plone.testing import layered -from plone.app.testing import layers - OPTIONFLAGS = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE +# Dummy handler used in tests +def dummy(context): + pass + def test_suite(): suite = unittest.TestSuite() suite.addTests([ + doctest.DocFileSuite('cleanup.txt', optionflags=OPTIONFLAGS), doctest.DocFileSuite('layers.txt', optionflags=OPTIONFLAGS), - layered( - doctest.DocFileSuite('helpers.txt',optionflags=OPTIONFLAGS), - layer=layers.PLONE_INTEGRATION_TESTING, - ), + doctest.DocFileSuite('helpers.txt',optionflags=OPTIONFLAGS), ]) return suite |