[Testbot] Plone 4.3 - Python 2.6 - Build # 2218 - Regression! - 68 failure(s)

jenkins at plone.org jenkins at plone.org
Fri Jul 18 18:52:41 UTC 2014


-------------------------------------------------------------------------------
Plone 4.3 - Python 2.6 - Build # 2218 - Failure!
-------------------------------------------------------------------------------

http://jenkins.plone.org/job/plone-4.3-python-2.6/2218/


-------------------------------------------------------------------------------
CHANGES
-------------------------------------------------------------------------------

Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-14T17:08:25+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/aca0a5c104c5d2bf01e3abdc3174c15afac49281

added testing buildout

Files changed:
A bootstrap.py
A buildout.cfg
M .gitignore

diff --git a/.gitignore b/.gitignore
index 0cf7321..3919a5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,12 @@
 *.egg-info
-*.pyc
-*.pyo
+*.py[co]
+*.mo
 build
 dist
 .project
 .pydevproject
 .settings
+.installed.cfg
+/bin
+/develop-eggs
+/parts
diff --git a/bootstrap.py b/bootstrap.py
new file mode 100644
index 0000000..ed57894
--- /dev/null
+++ b/bootstrap.py
@@ -0,0 +1,178 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --find-links to point to local resources, you can keep 
+this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
+                  help=("Specify the path to the buildout configuration "
+                        "file to be used."))
+parser.add_option("-f", "--find-links",
+                  help=("Specify a URL to search for buildout releases"))
+parser.add_option("--allow-site-packages",
+                  action="store_true", default=False,
+                  help=("Let bootstrap.py use existing site packages"))
+
+
+options, args = parser.parse_args()
+
+######################################################################
+# load/install setuptools
+
+try:
+    if options.allow_site_packages:
+        import setuptools
+        import pkg_resources
+    from urllib.request import urlopen
+except ImportError:
+    from urllib2 import urlopen
+
+ez = {}
+exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
+
+if not options.allow_site_packages:
+    # ez_setup imports site, which adds site packages
+    # this will remove them from the path to ensure that incompatible versions 
+    # of setuptools are not in the path
+    import site
+    # inside a virtualenv, there is no 'getsitepackages'. 
+    # We can't remove these reliably
+    if hasattr(site, 'getsitepackages'):
+        for sitepackage_path in site.getsitepackages():
+            sys.path[:] = [x for x in sys.path if sitepackage_path not in x]
+
+setup_args = dict(to_dir=tmpeggs, download_delay=0)
+ez['use_setuptools'](**setup_args)
+import setuptools
+import pkg_resources
+
+# This does not (always?) update the default working set.  We will
+# do it.
+for path in sys.path:
+    if path not in pkg_resources.working_set.entries:
+        pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
+ws = pkg_resources.working_set
+
+cmd = [sys.executable, '-c',
+       'from setuptools.command.easy_install import main; main()',
+       '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+    'bootstrap-testing-find-links',
+    options.find_links or
+    ('http://downloads.buildout.org/'
+     if options.accept_buildout_test_releases else None)
+    )
+if find_links:
+    cmd.extend(['-f', find_links])
+
+setuptools_path = ws.find(
+    pkg_resources.Requirement.parse('setuptools')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[setuptools_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
+    raise Exception(
+        "Failed to execute command:\n%s" % repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
+ws.add_entry(tmpeggs)
+ws.require(requirement)
+import zc.buildout.buildout
+
+if not [a for a in args if '=' not in a]:
+    args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args[0:0] = ['-c', options.config_file]
+
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
diff --git a/buildout.cfg b/buildout.cfg
new file mode 100644
index 0000000..56c4146
--- /dev/null
+++ b/buildout.cfg
@@ -0,0 +1,7 @@
+[buildout]
+extends = https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.x.cfg
+package-name = plone.app.contentrules
+package-extras = [test]
+
+[versions]
+plone.app.contentrules = 


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-14T17:09:26+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/ad187e215fe1acbcdde35e4528e04fb2e9dc36a0

specify Python and Plone version in setup.py

Files changed:
M setup.py

diff --git a/setup.py b/setup.py
index 9aa30ab..0746cf1 100644
--- a/setup.py
+++ b/setup.py
@@ -10,10 +10,12 @@
       classifiers=[
           "Environment :: Web Environment",
           "Framework :: Plone",
+          "Framework :: Plone :: 5.0",
           "Framework :: Zope2",
           "License :: OSI Approved :: GNU General Public License (GPL)",
           "Operating System :: OS Independent",
           "Programming Language :: Python",
+          "Programming Language :: Python :: 2.7",
         ],
       keywords='',
       author='Plone Foundation',


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-15T07:20:18+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/b38a9cedfb0687df439073396dd2154c49857371

switch to plone.app.testing

Files changed:
M plone/app/contentrules/tests/base.py
M setup.py

diff --git a/plone/app/contentrules/tests/base.py b/plone/app/contentrules/tests/base.py
index 238aaa4..2bb3927 100644
--- a/plone/app/contentrules/tests/base.py
+++ b/plone/app/contentrules/tests/base.py
@@ -1,25 +1,13 @@
-"""Base class for integration tests, based on ZopeTestCase and PloneTestCase.
-
-Note that importing this module has various side-effects: it registers a set of
-products with Zope, and it sets up a sandbox Plone site with the appropriate
-products installed.
+"""Base class for integration tests, based on plone.app.testing
 """
 
-# Import PloneTestCase - this registers more products with Zope as a side effect
-from Products.PloneTestCase.PloneTestCase import PloneTestCase
-from Products.PloneTestCase.PloneTestCase import FunctionalTestCase
-from Products.PloneTestCase.PloneTestCase import setupPloneSite
-from zope.component import getMultiAdapter
-
-# Set up a Plone site - note that the portlets branch of CMFPlone applies
-# a portlets profile.
-setupPloneSite()
+from plone.app.testing.bbb import PloneTestCase
 
 
 class ContentRulesTestCase(PloneTestCase):
-    """Base class for integration tests for plone.app.contentrules. This may
-    provide specific set-up and tear-down operations, or provide convenience
-    methods.
+    """Base class for integration tests for plone.app.contentrules.
+    This may provide specific set-up and tear-down operations, or provide
+    convenience methods.
     """
 
     def addAuthToRequest(self):
@@ -29,8 +17,8 @@ def addAuthToRequest(self):
         auth = authenticator.authenticator().split('value="')[1].rstrip('"/>')
         request.form['_authenticator'] = auth
 
-class ContentRulesFunctionalTestCase(FunctionalTestCase):
-    """Base class for functional integration tests for plone.app.portlets.
+class ContentRulesFunctionalTestCase(PloneTestCase):
+    """Base class for functional integration tests for plone.app.contentrules.
     This may provide specific set-up and tear-down operations, or provide
     convenience methods.
     """
diff --git a/setup.py b/setup.py
index 0746cf1..80a27ad 100644
--- a/setup.py
+++ b/setup.py
@@ -26,7 +26,7 @@
       namespace_packages = ['plone', 'plone.app'],
       include_package_data=True,
       zip_safe=False,
-      extras_require={'test': 'Products.PloneTestCase'},
+      extras_require={'test': 'plone.app.testing'},
       install_requires=[
         'setuptools',
         'five.formlib',


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-15T07:28:47+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/51d24287f582f188f275fd09ee370443a6b00d9e

remove unused imports reported by frosted

Files changed:
M plone/app/contentrules/browser/navigation.py
M plone/app/contentrules/handlers.py
M plone/app/contentrules/tests/base.py
M plone/app/contentrules/tests/test_action_copy.py
M plone/app/contentrules/tests/test_action_notify.py
M plone/app/contentrules/tests/test_cascading_rule.py

diff --git a/plone/app/contentrules/browser/navigation.py b/plone/app/contentrules/browser/navigation.py
index 7fb11ab..d1e18a4 100644
--- a/plone/app/contentrules/browser/navigation.py
+++ b/plone/app/contentrules/browser/navigation.py
@@ -7,7 +7,6 @@
 class RuleBreadcrumbs(PhysicalNavigationBreadcrumbs):
 
     def breadcrumbs(self):
-        base = super(RuleBreadcrumbs, self).breadcrumbs()
         portal_url = getToolByName(self.context, 'portal_url')()
         return ({'absolute_url': '%s/@@rules-controlpanel' % portal_url,
                  'Title': PloneMessageFactory('title_manage_contentrules', default=u"Content rules")},
diff --git a/plone/app/contentrules/handlers.py b/plone/app/contentrules/handlers.py
index d40fb07..5271020 100644
--- a/plone/app/contentrules/handlers.py
+++ b/plone/app/contentrules/handlers.py
@@ -7,7 +7,6 @@
 from zope.component.hooks import getSite
 
 from plone.app.discussion.interfaces import IComment
-from plone.contentrules.rule.interfaces import IRule
 from plone.contentrules.engine.interfaces import IRuleExecutor
 from plone.contentrules.engine.interfaces import IRuleStorage
 from plone.contentrules.engine.interfaces import StopRule
@@ -16,8 +15,6 @@
 from plone.uuid.interfaces import IUUID
 from Products.CMFCore.interfaces import ISiteRoot, IContentish
 from Products.CMFCore.utils import getToolByName
-from Products.ZCTextIndex.interfaces import IZCLexicon
-from AccessControl.userfolder import UserFolder
 
 try:
     from Products.Archetypes.interfaces import IBaseObject
diff --git a/plone/app/contentrules/tests/base.py b/plone/app/contentrules/tests/base.py
index 2bb3927..a171abe 100644
--- a/plone/app/contentrules/tests/base.py
+++ b/plone/app/contentrules/tests/base.py
@@ -2,6 +2,7 @@
 """
 
 from plone.app.testing.bbb import PloneTestCase
+from zope.component import getMultiAdapter
 
 
 class ContentRulesTestCase(PloneTestCase):
@@ -11,8 +12,8 @@ class ContentRulesTestCase(PloneTestCase):
     """
 
     def addAuthToRequest(self):
-        portal = self.portal
-        request = portal.REQUEST
+        portal = self.layer['portal']
+        request = self.layer['request']
         authenticator = getMultiAdapter((portal, request), name=u"authenticator")
         auth = authenticator.authenticator().split('value="')[1].rstrip('"/>')
         request.form['_authenticator'] = auth
diff --git a/plone/app/contentrules/tests/test_action_copy.py b/plone/app/contentrules/tests/test_action_copy.py
index 739150b..d802e97 100644
--- a/plone/app/contentrules/tests/test_action_copy.py
+++ b/plone/app/contentrules/tests/test_action_copy.py
@@ -9,12 +9,11 @@
 from plone.app.contentrules.actions.copy import CopyEditForm
 
 from plone.app.contentrules.rule import Rule
-
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 
-from zope.component.interfaces import IObjectEvent
+from plone.app.testing import TEST_USER_ID
 
-from Products.PloneTestCase.setup import default_user
+from zope.component.interfaces import IObjectEvent
 
 
 class DummyEvent(object):
@@ -29,7 +28,7 @@ class TestCopyAction(ContentRulesTestCase):
     def afterSetUp(self):
         self.loginAsPortalOwner()
         self.portal.invokeFactory('Folder', 'target')
-        self.login(default_user)
+        self.login()
         self.folder.invokeFactory('Document', 'd1')
 
     def testRegistered(self):
@@ -116,7 +115,7 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.folder.target.invokeFactory('Document', 'd1')
 
         e = CopyAction()
-        e.target_folder = '/Members/%s/target' % default_user
+        e.target_folder = '/Members/%s/target' % TEST_USER_ID
 
         ex = getMultiAdapter((self.folder.target, e, DummyEvent(self.folder.d1)), IExecutable)
         self.assertEqual(True, ex())
@@ -124,10 +123,3 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.assertTrue('d1' in self.folder.objectIds())
         self.assertTrue('d1' in self.folder.target.objectIds())
         self.assertTrue('d1.1' in self.folder.target.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestCopyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_notify.py b/plone/app/contentrules/tests/test_action_notify.py
index f450729..f73a38c 100644
--- a/plone/app/contentrules/tests/test_action_notify.py
+++ b/plone/app/contentrules/tests/test_action_notify.py
@@ -13,7 +13,6 @@
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 
 from Products.statusmessages import STATUSMESSAGEKEY
-from Products.statusmessages.interfaces import IStatusMessage
 from Products.statusmessages.adapter import _decodeCookieValue
 
 
@@ -25,6 +24,7 @@ class TestNotifyAction(ContentRulesTestCase):
 
     def afterSetUp(self):
         self.setRoles(('Manager', ))
+        self.request = self.layer['request']
 
     def testRegistered(self):
         element = getUtility(IRuleAction, name='plone.actions.Notify')
@@ -39,8 +39,8 @@ def testInvokeAddView(self):
         storage[u'foo'] = Rule()
         rule = self.portal.restrictedTraverse('++rule++foo')
 
-        adding = getMultiAdapter((rule, self.portal.REQUEST), name='+action')
-        addview = getMultiAdapter((adding, self.portal.REQUEST), name=element.addview)
+        adding = getMultiAdapter((rule, self.request), name='+action')
+        addview = getMultiAdapter((adding, self.request), name=element.addview)
 
         addview.createAndAdd(data={'message': 'Hello world', 'message_type': 'info'})
 
@@ -52,7 +52,7 @@ def testInvokeAddView(self):
     def testInvokeEditView(self):
         element = getUtility(IRuleAction, name='plone.actions.Notify')
         e = NotifyAction()
-        editview = getMultiAdapter((e, self.folder.REQUEST), name=element.editview)
+        editview = getMultiAdapter((e, self.request), name=element.editview)
         self.assertTrue(isinstance(editview, NotifyEditForm))
 
     def testExecute(self):
@@ -63,16 +63,8 @@ def testExecute(self):
         ex = getMultiAdapter((self.folder, e, DummyEvent()), IExecutable)
         self.assertEqual(True, ex())
 
-        status = IStatusMessage(self.app.REQUEST)
-        new_cookies = self.app.REQUEST.RESPONSE.cookies[STATUSMESSAGEKEY]
+        new_cookies = self.request.RESPONSE.cookies[STATUSMESSAGEKEY]
         messages = _decodeCookieValue(new_cookies['value'])
         self.assertEqual(1, len(messages))
         self.assertEqual('Hello world', messages[0].message)
         self.assertEqual('info', messages[0].type)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestNotifyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_cascading_rule.py b/plone/app/contentrules/tests/test_cascading_rule.py
index 70ed3d0..45f4fe2 100644
--- a/plone/app/contentrules/tests/test_cascading_rule.py
+++ b/plone/app/contentrules/tests/test_cascading_rule.py
@@ -1,29 +1,11 @@
 # -*- coding: utf-8 -*-
-
-import time
-
-from plone.contentrules.engine.interfaces import IRuleAssignmentManager
 from plone.contentrules.engine.interfaces import IRuleStorage
 from zope.component import getUtility
-from zope.component import getMultiAdapter
-from zope.lifecycleevent.interfaces import IObjectModifiedEvent
-
-from Products.GenericSetup.interfaces import IBody
-from Products.GenericSetup.context import TarballExportContext
-from Products.PloneTestCase.layer import PloneSite
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 from plone.app.contentrules.tests.test_configuration import TestContentrulesGSLayer
 from plone.app.contentrules.api import edit_rule_assignment
 
-# BBB Zope 2.12
-try:
-    from Zope2.App import zcml
-    from OFS import metaconfigure
-except ImportError:
-    from Products.Five import zcml
-    from Products.Five import fiveconfigure as metaconfigure
-
 
 class TestCascadingRule(ContentRulesTestCase):
 


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-18T14:42:49+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/ad299ebddf9218725ae4a000b7b1b8110fd07e24

fixed tests with plone.app.testing

Files changed:
A plone/app/contentrules/tests/testing.zcml
M plone/app/contentrules/tests/assignment.txt
M plone/app/contentrules/tests/multipublish.txt
M plone/app/contentrules/tests/simplepublish.txt
M plone/app/contentrules/tests/test_action_delete.py
M plone/app/contentrules/tests/test_action_logger.py
M plone/app/contentrules/tests/test_action_move.py
M plone/app/contentrules/tests/test_browser.py
M plone/app/contentrules/tests/test_configuration.py

diff --git a/plone/app/contentrules/tests/assignment.txt b/plone/app/contentrules/tests/assignment.txt
index bb74bab..95db1d2 100644
--- a/plone/app/contentrules/tests/assignment.txt
+++ b/plone/app/contentrules/tests/assignment.txt
@@ -1,28 +1,26 @@
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
+  >>> portal = layer['portal']
+  >>> if 'news' not in layer['portal']:
+  ...     obj = portal.invokeFactory('Folder', 'news')
+  >>> import transaction
+  >>> transaction.commit()
 
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
 
 Let's visit the control panel and add two content rules. They will be assigned
 at the root of the site. 
 
 First, we add a rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -63,7 +61,7 @@ Now comes the action, we want all news items to be copied into the
 
 A second rule will be added to notify users when a content is added.
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule', index=0).click()
diff --git a/plone/app/contentrules/tests/multipublish.txt b/plone/app/contentrules/tests/multipublish.txt
index e801071..f7325a7 100644
--- a/plone/app/contentrules/tests/multipublish.txt
+++ b/plone/app/contentrules/tests/multipublish.txt
@@ -4,26 +4,19 @@ during the same request.
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
-
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
+  >>> portal = layer['portal']
 
 Let's visit the control panel and add a content rule.  We'll add a
 rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -103,7 +96,7 @@ Now let's publish both simultaneously.
 
 Both news items should have moved into the `news/` folder now:
 
-  >>> browser.open(self.portal.absolute_url() + '/news/folder_listing')
+  >>> browser.open(portal.absolute_url() + '/news/folder_listing')
   >>> 'My news item' in browser.contents
   True
   >>> 'Second news item' in browser.contents
diff --git a/plone/app/contentrules/tests/simplepublish.txt b/plone/app/contentrules/tests/simplepublish.txt
index 45906f8..ae8044e 100644
--- a/plone/app/contentrules/tests/simplepublish.txt
+++ b/plone/app/contentrules/tests/simplepublish.txt
@@ -1,26 +1,24 @@
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
+  >>> portal = layer['portal']
+  >>> if 'news' not in portal:
+  ...     obj = portal.invokeFactory('Folder', 'news')
+  >>> import transaction
+  >>> transaction.commit()
 
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
 
 Let's visit the control panel and add a content rule.  We'll add a
 rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -85,8 +83,8 @@ Let's go back and create the news item now:
 
 The news item should have been copied into the `news/` folder now:
 
-  >>> 'my-news-item' in self.portal.news
+  >>> 'my-news-item' in portal.news
   True
 
-  >>> 'my-news-item' in self.portal
+  >>> 'my-news-item' in portal
   True
diff --git a/plone/app/contentrules/tests/test_action_delete.py b/plone/app/contentrules/tests/test_action_delete.py
index eb28b35..6d2f608 100644
--- a/plone/app/contentrules/tests/test_action_delete.py
+++ b/plone/app/contentrules/tests/test_action_delete.py
@@ -54,10 +54,3 @@ def testExecute(self):
         self.assertEqual(True, ex())
 
         self.assertFalse('d1' in self.folder.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestDeleteAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_logger.py b/plone/app/contentrules/tests/test_action_logger.py
index 4df16f7..4fd4631 100644
--- a/plone/app/contentrules/tests/test_action_logger.py
+++ b/plone/app/contentrules/tests/test_action_logger.py
@@ -12,6 +12,8 @@
 from plone.app.contentrules.rule import Rule
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
+from plone.app.testing import TEST_USER_ID
+from plone.app.testing import TEST_USER_NAME
 
 
 class DummyEvent(object):
@@ -24,8 +26,6 @@ class DummyObjectEvent(object):
     def __init__(self, obj):
         self.object = obj
 
-    pass
-
 
 class TestLoggerAction(ContentRulesTestCase):
 
@@ -71,7 +71,7 @@ def testProcessedMessage(self):
         self.assertEqual("Test log event", ex.processedMessage())
 
         e.message = "Test log event : &c"
-        self.assertEqual("Test log event : <ATFolder at /plone/Members/test_user_1_>",
+        self.assertEqual("Test log event : <ATFolder at /plone/Members/%s>" % TEST_USER_ID,
                           ex.processedMessage())
 
         e.message = "Test log event : &e"
@@ -79,7 +79,7 @@ def testProcessedMessage(self):
                           ex.processedMessage())
 
         e.message = "Test log event : &u"
-        self.assertEqual("Test log event : test_user_1_", ex.processedMessage())
+        self.assertEqual("Test log event : %s" % TEST_USER_NAME, ex.processedMessage())
 
     def testExecute(self):
         e = LoggerAction()
@@ -87,11 +87,4 @@ def testExecute(self):
         e.loggingLevel = 0
         e.message = "Test log event"
         ex = getMultiAdapter((self.folder, e, DummyEvent()), IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestLoggerAction))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_action_move.py b/plone/app/contentrules/tests/test_action_move.py
index 41f3677..d6bcf45 100644
--- a/plone/app/contentrules/tests/test_action_move.py
+++ b/plone/app/contentrules/tests/test_action_move.py
@@ -14,7 +14,7 @@
 
 from zope.component.interfaces import IObjectEvent
 
-from Products.PloneTestCase.setup import default_user
+from plone.app.testing import TEST_USER_ID as default_user
 
 
 class DummyEvent(object):
@@ -29,7 +29,7 @@ class TestMoveAction(ContentRulesTestCase):
     def afterSetUp(self):
         self.loginAsPortalOwner()
         self.portal.invokeFactory('Folder', 'target')
-        self.login(default_user)
+        self.login()
         self.folder.invokeFactory('Document', 'd1')
 
     def testRegistered(self):
diff --git a/plone/app/contentrules/tests/test_browser.py b/plone/app/contentrules/tests/test_browser.py
index 14b0cda..bd03f76 100644
--- a/plone/app/contentrules/tests/test_browser.py
+++ b/plone/app/contentrules/tests/test_browser.py
@@ -1,22 +1,20 @@
 import unittest
+import doctest
 
-from Testing.ZopeTestCase import FunctionalDocFileSuite as Suite
-from Products.PloneTestCase import PloneTestCase as ptc
-from Products.PloneTestCase.PloneTestCase import setupPloneSite
+from plone.app.testing.bbb import PTC_FUNCTIONAL_TESTING
+from plone.testing import layered
 
-setupPloneSite()
 
+optionflags = (doctest.NORMALIZE_WHITESPACE|
+               doctest.ELLIPSIS|
+               doctest.REPORT_NDIFF)
 
-def test_suite():
-    suites = [
-        Suite('assignment.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase),
-        Suite('simplepublish.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase),
-        Suite('multipublish.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase)]
 
-    return unittest.TestSuite(suites)
+def test_suite():
+    suite = unittest.TestSuite()
+    for doc in ['assignment.txt', 'simplepublish.txt', 'multipublish.txt']:
+        suite.addTest(layered(
+            doctest.DocFileSuite(doc, package='plone.app.contentrules.tests',
+                                 optionflags=optionflags),
+            layer=PTC_FUNCTIONAL_TESTING))
+    return suite
diff --git a/plone/app/contentrules/tests/test_configuration.py b/plone/app/contentrules/tests/test_configuration.py
index 8e354d0..00452e9 100644
--- a/plone/app/contentrules/tests/test_configuration.py
+++ b/plone/app/contentrules/tests/test_configuration.py
@@ -10,49 +10,24 @@
 
 from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.context import TarballExportContext
-from Products.PloneTestCase.layer import PloneSite
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
+from plone.app.testing.bbb import PloneTestCaseFixture
+from plone.app.testing import FunctionalTesting
 
-# BBB Zope 2.12
-try:
-    from Zope2.App import zcml
-    from OFS import metaconfigure
-except ImportError:
-    from Products.Five import zcml
-    from Products.Five import fiveconfigure as metaconfigure
-
-
-zcml_string = """\
-<configure xmlns="http://namespaces.zope.org/zope"
-           xmlns:gs="http://namespaces.zope.org/genericsetup"
-           package="plone.app.contentrules"
-           i18n_domain="plone">
-
-    <gs:registerProfile
-        name="testing"
-        title="plone.app.contentrules testing"
-        description="Used for testing only"
-        directory="tests/profiles/testing"
-        for="Products.CMFCore.interfaces.ISiteRoot"
-        provides="Products.GenericSetup.interfaces.EXTENSION"
-        />
-
-</configure>
-"""
 
+class TestContentrulesGSFixture(PloneTestCaseFixture):
 
-class TestContentrulesGSLayer(PloneSite):
+        def setUpZope(self, app, configurationContext):
+            super(TestContentrulesGSFixture,
+                  self).setUpZope(app, configurationContext)
+            import plone.app.contentrules.tests
+            self.loadZCML('testing.zcml', package=plone.app.contentrules.tests)
 
-    @classmethod
-    def setUp(cls):
-        metaconfigure.debug_mode = True
-        zcml.load_string(zcml_string)
-        metaconfigure.debug_mode = False
 
-    @classmethod
-    def tearDown(cls):
-        pass
+ContentrulesGSFixture = TestContentrulesGSFixture()
+TestContentrulesGSLayer = FunctionalTesting(bases=(ContentrulesGSFixture,),
+                                            name='TestContentRules:Functional')
 
 
 class TestGenericSetup(ContentRulesTestCase):
@@ -239,10 +214,3 @@ def testExport(self):
 
         body = exporter.body
         self.assertEqual(expected.strip(), body.strip(), body)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestGenericSetup))
-    return suite
diff --git a/plone/app/contentrules/tests/testing.zcml b/plone/app/contentrules/tests/testing.zcml
new file mode 100644
index 0000000..80dcd4d
--- /dev/null
+++ b/plone/app/contentrules/tests/testing.zcml
@@ -0,0 +1,15 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:gs="http://namespaces.zope.org/genericsetup"
+           package="plone.app.contentrules"
+           i18n_domain="plone">
+
+    <gs:registerProfile
+        name="testing"
+        title="plone.app.contentrules testing"
+        description="Used for testing only"
+        directory="tests/profiles/testing"
+        for="Products.CMFCore.interfaces.ISiteRoot"
+        provides="Products.GenericSetup.interfaces.EXTENSION"
+        />
+
+</configure>


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-18T14:53:48+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/8b570285dd92a99e9fa7e1f07c1ba9d866cf5b6c

removed test-suites. tests are collected by testrunner anyway

Files changed:
M plone/app/contentrules/tests/test_action_mail.py
M plone/app/contentrules/tests/test_action_modify.py
M plone/app/contentrules/tests/test_action_move.py
M plone/app/contentrules/tests/test_action_workflow.py
M plone/app/contentrules/tests/test_cascading_rule.py
M plone/app/contentrules/tests/test_condition_group.py
M plone/app/contentrules/tests/test_condition_portal_type.py
M plone/app/contentrules/tests/test_condition_role.py
M plone/app/contentrules/tests/test_condition_tales_expression.py
M plone/app/contentrules/tests/test_condition_wfstate.py
M plone/app/contentrules/tests/test_condition_wftransition.py
M plone/app/contentrules/tests/test_events.py
M plone/app/contentrules/tests/test_handlers.py
M plone/app/contentrules/tests/test_rule_assignment_mapping.py
M plone/app/contentrules/tests/test_rule_management_views.py
M plone/app/contentrules/tests/test_setup.py
M plone/app/contentrules/tests/test_traversal.py

diff --git a/plone/app/contentrules/tests/test_action_mail.py b/plone/app/contentrules/tests/test_action_mail.py
index 6a8aac3..ffcff67 100644
--- a/plone/app/contentrules/tests/test_action_mail.py
+++ b/plone/app/contentrules/tests/test_action_mail.py
@@ -228,10 +228,3 @@ def testExecuteBadMailHost(self):
         ex = getMultiAdapter((self.folder, e, DummyEvent(self.folder.d1)),
                              IExecutable)
         ex()
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestMailAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_modify.py b/plone/app/contentrules/tests/test_action_modify.py
index 22b5ceb..10cb428 100644
--- a/plone/app/contentrules/tests/test_action_modify.py
+++ b/plone/app/contentrules/tests/test_action_modify.py
@@ -38,10 +38,3 @@ class Content(object):
             __name__ = None
         handlers.modified(ObjectRemovedEvent(Content()))
         self.assertFalse(self.called)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestModifyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_move.py b/plone/app/contentrules/tests/test_action_move.py
index d6bcf45..e29ffcb 100644
--- a/plone/app/contentrules/tests/test_action_move.py
+++ b/plone/app/contentrules/tests/test_action_move.py
@@ -142,10 +142,3 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.assertFalse('d1' in self.folder.objectIds())
         self.assertTrue('d1' in self.folder.target.objectIds())
         self.assertTrue('d1.1' in self.folder.target.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestMoveAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_workflow.py b/plone/app/contentrules/tests/test_action_workflow.py
index 0aaa0ff..e55b3c8 100644
--- a/plone/app/contentrules/tests/test_action_workflow.py
+++ b/plone/app/contentrules/tests/test_action_workflow.py
@@ -75,10 +75,3 @@ def testExecuteWithError(self):
         self.assertEqual(False, ex())
 
         self.assertEqual(old_state, self.portal.portal_workflow.getInfoFor(self.folder.d1, 'review_state'))
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_cascading_rule.py b/plone/app/contentrules/tests/test_cascading_rule.py
index 45f4fe2..4e050a0 100644
--- a/plone/app/contentrules/tests/test_cascading_rule.py
+++ b/plone/app/contentrules/tests/test_cascading_rule.py
@@ -37,12 +37,5 @@ def test_cascading_rule(self):
         self.assertTrue('my-event' in self.portal.events)
 
         wtool = self.portal.portal_workflow
-        self.assertTrue(wtool.getInfoFor(self.portal.events['my-event'], 'review_state'),
+        self.assertEqual(wtool.getInfoFor(self.portal.events['my-event'], 'review_state'),
                         'published')
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestCascadingRule))
-    return suite
diff --git a/plone/app/contentrules/tests/test_condition_group.py b/plone/app/contentrules/tests/test_condition_group.py
index bd5f4c9..8fbe0fd 100644
--- a/plone/app/contentrules/tests/test_condition_group.py
+++ b/plone/app/contentrules/tests/test_condition_group.py
@@ -60,17 +60,10 @@ def testExecute(self):
         e.group_names = ['Administrators', 'Reviewers']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         group = self.portal.portal_groups.getGroupById('Administrators')
         group.addMember(self.portal.portal_membership.getAuthenticatedMember().getId())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestGroupCondition))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_condition_portal_type.py b/plone/app/contentrules/tests/test_condition_portal_type.py
index 1475fef..de5fa3b 100644
--- a/plone/app/contentrules/tests/test_condition_portal_type.py
+++ b/plone/app/contentrules/tests/test_condition_portal_type.py
@@ -60,18 +60,11 @@ def testExecute(self):
         e.check_types = ['Folder', 'Image']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         self.folder.portal_types = None
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestPortalTypeCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_role.py b/plone/app/contentrules/tests/test_condition_role.py
index 7ee74ac..7343976 100644
--- a/plone/app/contentrules/tests/test_condition_role.py
+++ b/plone/app/contentrules/tests/test_condition_role.py
@@ -60,16 +60,9 @@ def testExecute(self):
         e.role_names = ['Manager', 'Member']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         e.role_names = ['Reviewer']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRoleCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_tales_expression.py b/plone/app/contentrules/tests/test_condition_tales_expression.py
index 332aba4..c04fb83 100644
--- a/plone/app/contentrules/tests/test_condition_tales_expression.py
+++ b/plone/app/contentrules/tests/test_condition_tales_expression.py
@@ -73,10 +73,3 @@ def testExecuteUnicodeString(self):
         e.tales_expression = u'string:${portal_url}'
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
         self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestTalesExpressionCondition))
-    return suite
diff --git a/plone/app/contentrules/tests/test_condition_wfstate.py b/plone/app/contentrules/tests/test_condition_wfstate.py
index cf2a6cd..b70bb57 100644
--- a/plone/app/contentrules/tests/test_condition_wfstate.py
+++ b/plone/app/contentrules/tests/test_condition_wfstate.py
@@ -60,19 +60,12 @@ def testExecute(self):
         e.wf_states = ['visible', 'private']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         self.portal.portal_workflow.doActionFor(self.folder, 'publish')
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowStateCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_wftransition.py b/plone/app/contentrules/tests/test_condition_wftransition.py
index 8fbc200..e7ed2f9 100644
--- a/plone/app/contentrules/tests/test_condition_wftransition.py
+++ b/plone/app/contentrules/tests/test_condition_wftransition.py
@@ -55,21 +55,14 @@ def testExecute(self):
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'publish', None)),
                              IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'retract', None)),
                              IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'hide', None)),
                              IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowTransitionCondition))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_events.py b/plone/app/contentrules/tests/test_events.py
index e7ac471..c4a677a 100644
--- a/plone/app/contentrules/tests/test_events.py
+++ b/plone/app/contentrules/tests/test_events.py
@@ -10,10 +10,3 @@ def testEventHandlerExecutesRules(self):
     def testEventHandlerExecutesRulesOnlyOnce(self):
         # XXX Test missing
         pass
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestEvents))
-    return suite
diff --git a/plone/app/contentrules/tests/test_handlers.py b/plone/app/contentrules/tests/test_handlers.py
index b9fa8cd..99460fe 100644
--- a/plone/app/contentrules/tests/test_handlers.py
+++ b/plone/app/contentrules/tests/test_handlers.py
@@ -54,10 +54,3 @@ def test_delayed_events(self):
         handlers.added(event2)
         from plone.app.contentrules.handlers import _status
         self.assertEqual(len(_status.delayed_events), 2)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestDuplicateRuleFilter))
-    return suite
diff --git a/plone/app/contentrules/tests/test_rule_assignment_mapping.py b/plone/app/contentrules/tests/test_rule_assignment_mapping.py
index 8f956bc..952dfd3 100644
--- a/plone/app/contentrules/tests/test_rule_assignment_mapping.py
+++ b/plone/app/contentrules/tests/test_rule_assignment_mapping.py
@@ -127,10 +127,3 @@ def testRuleAssignmentAddedAPI(self):
         self.assertFalse(self.f11a['r3'].bubbles)
 
         self.assertEqual(self.f11a.keys(), ['r1', 'r3', 'r2'])
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRuleAssignmentMapping))
-    return suite
diff --git a/plone/app/contentrules/tests/test_rule_management_views.py b/plone/app/contentrules/tests/test_rule_management_views.py
index 8be252e..4e2c73d 100644
--- a/plone/app/contentrules/tests/test_rule_management_views.py
+++ b/plone/app/contentrules/tests/test_rule_management_views.py
@@ -155,10 +155,3 @@ def testChangeGloballyEnable(self):
 
         # without ajax
         self.portal.REQUEST.form
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRuleManagementViews))
-    suite.addTest(makeSuite(TestRuleElementManagementViews))
-    return suite
diff --git a/plone/app/contentrules/tests/test_setup.py b/plone/app/contentrules/tests/test_setup.py
index f665051..6461322 100644
--- a/plone/app/contentrules/tests/test_setup.py
+++ b/plone/app/contentrules/tests/test_setup.py
@@ -18,10 +18,3 @@ def testEventTypesMarked(self):
         self.assertTrue(IRuleEventType.providedBy(IObjectAddedEvent))
         self.assertTrue(IRuleEventType.providedBy(IObjectModifiedEvent))
         self.assertTrue(IRuleEventType.providedBy(IObjectRemovedEvent))
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestProductInstall))
-    return suite
diff --git a/plone/app/contentrules/tests/test_traversal.py b/plone/app/contentrules/tests/test_traversal.py
index 0bfe975..a91e4d9 100644
--- a/plone/app/contentrules/tests/test_traversal.py
+++ b/plone/app/contentrules/tests/test_traversal.py
@@ -68,10 +68,3 @@ def testTraverseToRuleAction(self):
 
         self.assertTrue(aq_parent(te2) is tr)
         self.assertEqual("y", te2.x)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestTraversal))
-    return suite


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-18T14:54:35+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/ab194e67b459f7a7d94c9985bc130e386181aceb

document changes

Files changed:
M CHANGES.rst

diff --git a/CHANGES.rst b/CHANGES.rst
index c630d1b..21566d4 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,7 +4,8 @@ Changelog
 3.0.8 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Ported tests to plone.app.testing
+  [tomgross]
 
 
 3.0.7 (2014-04-13)


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-18T15:53:48+02:00
Author: Tom Gross (tomgross) <itconsense at gmail.com>
Commit: https://github.com/plone/plone.app.contentrules/commit/90ea2a1b0eaf4640c3281fbec198efddede27bb2

automatic pep8ify cleanups

Files changed:
M .gitignore
M plone/app/contentrules/actions/logger.py
M plone/app/contentrules/actions/mail.py
M plone/app/contentrules/api.py
M plone/app/contentrules/browser/assignments.py
M plone/app/contentrules/browser/controlpanel.py
M plone/app/contentrules/browser/elements.py
M plone/app/contentrules/browser/resources.py
M plone/app/contentrules/conditions/fileextension.py
M plone/app/contentrules/conditions/portaltype.py
M plone/app/contentrules/exportimport/rules.py
M plone/app/contentrules/handlers.py
M plone/app/contentrules/namechooser.py
M plone/app/contentrules/tests/base.py
M plone/app/contentrules/tests/test_action_move.py
M plone/app/contentrules/tests/test_browser.py
M plone/app/contentrules/tests/test_configuration.py
M plone/app/contentrules/tests/test_rule_management_views.py

diff --git a/.gitignore b/.gitignore
index 3919a5d..4decf05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ dist
 /bin
 /develop-eggs
 /parts
+*.bak
diff --git a/plone/app/contentrules/actions/logger.py b/plone/app/contentrules/actions/logger.py
index 059b1f4..c6083f0 100644
--- a/plone/app/contentrules/actions/logger.py
+++ b/plone/app/contentrules/actions/logger.py
@@ -14,7 +14,6 @@
 from plone.app.contentrules import PloneMessageFactory as _
 from plone.app.contentrules.browser.formhelper import AddForm, EditForm
 
-
 logger = logging.getLogger("plone.contentrules.logger")
 handler = logging.StreamHandler()
 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s -  %(message)s")
@@ -32,7 +31,7 @@ class ILoggerAction(Interface):
                                     default='Plone')
 
     loggingLevel = schema.Int(title=_(u'Logging level'),
-                              default=20) # INFO
+                              default=20)  # INFO
 
     message = schema.TextLine(title=_(u"Message"),
                               description=_('help_contentrules_logger_message',
diff --git a/plone/app/contentrules/actions/mail.py b/plone/app/contentrules/actions/mail.py
index d25dbac..5cde935 100644
--- a/plone/app/contentrules/actions/mail.py
+++ b/plone/app/contentrules/actions/mail.py
@@ -21,7 +21,6 @@
 from plone.app.contentrules import PloneMessageFactory as _
 from plone.app.contentrules.browser.formhelper import AddForm, EditForm
 
-
 logger = logging.getLogger("plone.contentrules")
 
 
@@ -118,7 +117,7 @@ def __call__(self):
             source = '"%s" <%s>' % (from_name, from_address)
 
         recip_string = interpolator(self.element.recipients)
-        if recip_string: # check recipient is not None or empty string
+        if recip_string:  # check recipient is not None or empty string
             recipients = set([str(mail.strip()) for mail in recip_string.split(',') \
                               if mail.strip()])
         else:
diff --git a/plone/app/contentrules/api.py b/plone/app/contentrules/api.py
index d6612a7..d9f7bc3 100644
--- a/plone/app/contentrules/api.py
+++ b/plone/app/contentrules/api.py
@@ -1,6 +1,6 @@
 from zope.component import queryUtility
 from plone.contentrules.engine.assignments import RuleAssignment
-from plone.contentrules.engine.interfaces import IRuleStorage,\
+from plone.contentrules.engine.interfaces import IRuleStorage, \
     IRuleAssignmentManager
 from plone.app.contentrules.rule import get_assignments, insert_assignment
 
diff --git a/plone/app/contentrules/browser/assignments.py b/plone/app/contentrules/browser/assignments.py
index b255c0d..c96d4eb 100644
--- a/plone/app/contentrules/browser/assignments.py
+++ b/plone/app/contentrules/browser/assignments.py
@@ -34,14 +34,14 @@ def __call__(self):
             keys = list(assignable.keys())
             idx = keys.index(rule_id)
             del keys[idx]
-            keys.insert(idx-1, rule_id)
+            keys.insert(idx - 1, rule_id)
             assignable.updateOrder(keys)
         elif operation == 'move_down':
             rule_id = request.get('rule_id')
             keys = list(assignable.keys())
             idx = keys.index(rule_id)
             del keys[idx]
-            keys.insert(idx+1, rule_id)
+            keys.insert(idx + 1, rule_id)
             assignable.updateOrder(keys)
         elif 'form.button.AddAssignment' in form:
             rule_id = form.get('rule_id')
@@ -115,12 +115,12 @@ def acquired_rules(self):
                     if key not in in_use and assignment.bubbles:
                         rule = storage.get(key, None)
                         if rule is not None:
-                            assignments.append(dict(id = key,
-                                                    title = rule.title,
-                                                    description = rule.description,
-                                                    trigger = events.get(rule.event, "Unknown"),
-                                                    url = context.absolute_url() + '/@@manage-content-rules',
-                                                    enabled = (assignment.enabled and rule.enabled), ))
+                            assignments.append(dict(id=key,
+                                                    title=rule.title,
+                                                    description=rule.description,
+                                                    trigger=events.get(rule.event, "Unknown"),
+                                                    url=context.absolute_url() + '/@@manage-content-rules',
+                                                    enabled=(assignment.enabled and rule.enabled), ))
             if ISiteRoot.providedBy(context):
                 context = None
             else:
@@ -138,14 +138,14 @@ def assigned_rules(self):
         for key, assignment in assignable.items():
             rule = storage.get(key, None)
             if rule is not None:
-                assignments.append(dict(id = key,
-                                        title = rule.title,
-                                        description = rule.description,
-                                        trigger = events.get(rule.event, "Unknown"),
-                                        url = self._rule_url(key),
-                                        bubbles = assignment.bubbles,
-                                        enabled = assignment.enabled,
-                                        global_enabled = rule.enabled, ))
+                assignments.append(dict(id=key,
+                                        title=rule.title,
+                                        description=rule.description,
+                                        trigger=events.get(rule.event, "Unknown"),
+                                        url=self._rule_url(key),
+                                        bubbles=assignment.bubbles,
+                                        enabled=assignment.enabled,
+                                        global_enabled=rule.enabled, ))
         return assignments
 
     def has_rules(self):
@@ -156,9 +156,9 @@ def assignable_rules(self):
         assignable = []
         for key, rule in getUtility(IRuleStorage).items():
             if key not in in_use:
-                assignable.append(dict(id = key,
-                                       title = rule.title,
-                                       description = rule.description, ))
+                assignable.append(dict(id=key,
+                                       title=rule.title,
+                                       description=rule.description, ))
         return assignable
 
     @memoize
diff --git a/plone/app/contentrules/browser/controlpanel.py b/plone/app/contentrules/browser/controlpanel.py
index bbdf443..0a3aaa3 100644
--- a/plone/app/contentrules/browser/controlpanel.py
+++ b/plone/app/contentrules/browser/controlpanel.py
@@ -15,6 +15,7 @@
 from plone.app.contentrules.rule import get_assignments
 from Products.statusmessages.interfaces import IStatusMessage
 
+
 def get_trigger_class(trigger):
     return "trigger-%s" % trigger.__identifier__.split('.')[-1].lower()
 
diff --git a/plone/app/contentrules/browser/elements.py b/plone/app/contentrules/browser/elements.py
index f7f6c8f..b125b0a 100644
--- a/plone/app/contentrules/browser/elements.py
+++ b/plone/app/contentrules/browser/elements.py
@@ -102,7 +102,7 @@ def rule_event(self):
             if e.value == self.context.event:
                 return translate(e.token, context=self.request, domain='plone')
 
-        return "Unknown event" # should not happen
+        return "Unknown event"  # should not happen
 
     @memoize
     def actions(self):
@@ -196,13 +196,13 @@ def _populate_info(self, elements, meta, namespace):
                 editview = '%s/++%s++%d/%s' % (base_url, namespace, idx,
                                                descriptor.editview, )
 
-            info.append({'title'      : descriptor.title,
+            info.append({'title': descriptor.title,
                          'description': descriptor.description,
-                         'summary'    : data.summary,
-                         'editview'   : editview,
-                         'first'      : (idx == 0),
-                         'last'       : (idx == last),
-                         'idx'        : idx,
+                         'summary': data.summary,
+                         'editview': editview,
+                         'first': (idx == 0),
+                         'last': (idx == last),
+                         'idx': idx,
                         })
         return info
 
diff --git a/plone/app/contentrules/browser/resources.py b/plone/app/contentrules/browser/resources.py
index c01df75..1a37d42 100644
--- a/plone/app/contentrules/browser/resources.py
+++ b/plone/app/contentrules/browser/resources.py
@@ -5,4 +5,4 @@ class Resources(ViewletBase):
 
     def render(self):
         return u"""
-      """ % {'portal_url': self.site_url}
\ No newline at end of file
+      """ % {'portal_url': self.site_url}
diff --git a/plone/app/contentrules/conditions/fileextension.py b/plone/app/contentrules/conditions/fileextension.py
index 6156b43..036e565 100644
--- a/plone/app/contentrules/conditions/fileextension.py
+++ b/plone/app/contentrules/conditions/fileextension.py
@@ -66,7 +66,7 @@ def __call__(self):
             return False
 
         name = get_filename()
-        extension = name[name.rfind('.')+1:]
+        extension = name[name.rfind('.') + 1:]
         return extension == self.element.file_extension
 
 
diff --git a/plone/app/contentrules/conditions/portaltype.py b/plone/app/contentrules/conditions/portaltype.py
index 54bfdc7..ef8a90b 100644
--- a/plone/app/contentrules/conditions/portaltype.py
+++ b/plone/app/contentrules/conditions/portaltype.py
@@ -71,7 +71,7 @@ def __call__(self):
             # types tool have a getTypeInfo method
             return False
 
-        ti = obj.getTypeInfo() # getTypeInfo can be None
+        ti = obj.getTypeInfo()  # getTypeInfo can be None
         if ti is None:
             return False
         return ti.getId() in self.element.check_types
diff --git a/plone/app/contentrules/exportimport/rules.py b/plone/app/contentrules/exportimport/rules.py
index a2d8e54..c08592b 100644
--- a/plone/app/contentrules/exportimport/rules.py
+++ b/plone/app/contentrules/exportimport/rules.py
@@ -69,8 +69,6 @@ def export_element(self, doc, node):
 
             child = self.export_field(doc, field)
             node.appendChild(child)
-
-
     # Helper methods
 
     def import_node(self, interface, child):
@@ -237,7 +235,6 @@ def _initRules(self, node):
                 rule.enabled = as_bool(child.getAttribute('enabled'), True)
                 rule.stop = as_bool(child.getAttribute('stop-after'))
                 rule.cascading = as_bool(child.getAttribute('cascading'))
-
                 # Aq-wrap to enable complex setters for elements below
                 # to work
 
@@ -323,7 +320,6 @@ def _extractRules(self):
             rule_node.setAttribute('enabled', str(rule.enabled))
             rule_node.setAttribute('stop-after', str(rule.stop))
             rule_node.setAttribute('cascading', str(rule.cascading))
-
             # Aq-wrap so that exporting fields with clever getters or
             # vocabularies will work. We also aq-wrap conditions and
             # actions below.
@@ -360,7 +356,6 @@ def _extractRules(self):
 
             fragment.appendChild(rule_node)
             assignment_paths.update(get_assignments(rule))
-
         # Export assignments last - this is necessary to ensure they
         # are orderd properly
 
@@ -397,7 +392,7 @@ def importRules(context):
         filename = '%s%s' % (importer.name, importer.suffix)
         body = context.readDataFile(filename)
         if body is not None:
-            importer.filename = filename # for error reporting
+            importer.filename = filename  # for error reporting
             importer.body = body
 
 
diff --git a/plone/app/contentrules/handlers.py b/plone/app/contentrules/handlers.py
index 5271020..4cece16 100644
--- a/plone/app/contentrules/handlers.py
+++ b/plone/app/contentrules/handlers.py
@@ -1,7 +1,7 @@
 import threading
 
 from zope.component import queryUtility
-from zope.container.interfaces import IObjectAddedEvent, IObjectRemovedEvent,\
+from zope.container.interfaces import IObjectAddedEvent, IObjectRemovedEvent, \
     IContainerModifiedEvent
 from zope.interface import Interface
 from zope.component.hooks import getSite
@@ -23,6 +23,8 @@
 except ImportError:
     class IBaseObject(Interface):
         pass
+
+
     class IObjectInitializedEvent(Interface):
         pass
     HAS_ARCHETYPES = False
@@ -137,10 +139,8 @@ def execute(context, event):
     # execute rules again
     rule_filter.in_progress = False
 
-
 # Event handlers
 
-
 def is_portal_factory(context):
     """Find out if the given object is in portal_factory
     """
diff --git a/plone/app/contentrules/namechooser.py b/plone/app/contentrules/namechooser.py
index efa7f43..fc2978b 100644
--- a/plone/app/contentrules/namechooser.py
+++ b/plone/app/contentrules/namechooser.py
@@ -2,7 +2,6 @@
 from zope.container.interfaces import INameChooser
 from zope.interface import implements
 
-
 ATTEMPTS = 100
 
 
diff --git a/plone/app/contentrules/tests/base.py b/plone/app/contentrules/tests/base.py
index a171abe..05a7bdd 100644
--- a/plone/app/contentrules/tests/base.py
+++ b/plone/app/contentrules/tests/base.py
@@ -18,6 +18,7 @@ def addAuthToRequest(self):
         auth = authenticator.authenticator().split('value="')[1].rstrip('"/>')
         request.form['_authenticator'] = auth
 
+
 class ContentRulesFunctionalTestCase(PloneTestCase):
     """Base class for functional integration tests for plone.app.contentrules.
     This may provide specific set-up and tear-down operations, or provide
diff --git a/plone/app/contentrules/tests/test_action_move.py b/plone/app/contentrules/tests/test_action_move.py
index e29ffcb..b5a9c60 100644
--- a/plone/app/contentrules/tests/test_action_move.py
+++ b/plone/app/contentrules/tests/test_action_move.py
@@ -71,7 +71,7 @@ def testExecute(self):
         self.assertTrue('d1' in self.portal.target.objectIds())
 
         # test catalog is ok
-        brains  = self.portal.portal_catalog(id='d1')
+        brains = self.portal.portal_catalog(id='d1')
         self.assertEqual(len(brains), 1)
         self.assertEqual(brains[0].getPath(), '/plone/target/d1')
 
diff --git a/plone/app/contentrules/tests/test_browser.py b/plone/app/contentrules/tests/test_browser.py
index bd03f76..e2a4d9f 100644
--- a/plone/app/contentrules/tests/test_browser.py
+++ b/plone/app/contentrules/tests/test_browser.py
@@ -4,9 +4,8 @@
 from plone.app.testing.bbb import PTC_FUNCTIONAL_TESTING
 from plone.testing import layered
 
-
-optionflags = (doctest.NORMALIZE_WHITESPACE|
-               doctest.ELLIPSIS|
+optionflags = (doctest.NORMALIZE_WHITESPACE |
+               doctest.ELLIPSIS |
                doctest.REPORT_NDIFF)
 
 
diff --git a/plone/app/contentrules/tests/test_configuration.py b/plone/app/contentrules/tests/test_configuration.py
index 00452e9..f146cff 100644
--- a/plone/app/contentrules/tests/test_configuration.py
+++ b/plone/app/contentrules/tests/test_configuration.py
@@ -18,15 +18,14 @@
 
 class TestContentrulesGSFixture(PloneTestCaseFixture):
 
-        def setUpZope(self, app, configurationContext):
-            super(TestContentrulesGSFixture,
+    def setUpZope(self, app, configurationContext):
+        super(TestContentrulesGSFixture,
                   self).setUpZope(app, configurationContext)
-            import plone.app.contentrules.tests
-            self.loadZCML('testing.zcml', package=plone.app.contentrules.tests)
-
+        import plone.app.contentrules.tests
+        self.loadZCML('testing.zcml', package=plone.app.contentrules.tests)
 
 ContentrulesGSFixture = TestContentrulesGSFixture()
-TestContentrulesGSLayer = FunctionalTesting(bases=(ContentrulesGSFixture,),
+TestContentrulesGSLayer = FunctionalTesting(bases=(ContentrulesGSFixture, ),
                                             name='TestContentRules:Functional')
 
 
@@ -102,7 +101,7 @@ def testImportTwice(self):
         # Ensure rules, actions/conditions and assignments are not duplicated
         # if the profile is re-imported; see bug #8027.
         portal_setup = self.portal.portal_setup
-        time.sleep(1) # avoid timestamp colission
+        time.sleep(1)  # avoid timestamp colission
         portal_setup.runAllImportStepsFromProfile('profile-plone.app.contentrules:testing')
 
         # We should get the same results as before
diff --git a/plone/app/contentrules/tests/test_rule_management_views.py b/plone/app/contentrules/tests/test_rule_management_views.py
index 4e2c73d..5df6cc1 100644
--- a/plone/app/contentrules/tests/test_rule_management_views.py
+++ b/plone/app/contentrules/tests/test_rule_management_views.py
@@ -138,7 +138,6 @@ def testRulesControlPanel(self):
         registered_rules = controlpanel.registeredRules()
         self.assertEqual(0, len(registered_rules))
 
-
     def testChangeGloballyEnable(self):
         storage = getUtility(IRuleStorage)
         portal = self.portal


Repository: plone.app.contentrules
Branch: refs/heads/master
Date: 2014-07-18T19:59:21+02:00
Author: Timo Stollenwerk (tisto) <tisto at plone.org>
Commit: https://github.com/plone/plone.app.contentrules/commit/45caaf68df8730706cd593648df0d436431766e5

Merge pull request #6 from plone/tomgross-ptc

Ported tests to plone.app.testing

Files changed:
A bootstrap.py
A buildout.cfg
A plone/app/contentrules/tests/testing.zcml
M .gitignore
M CHANGES.rst
M plone/app/contentrules/actions/logger.py
M plone/app/contentrules/actions/mail.py
M plone/app/contentrules/api.py
M plone/app/contentrules/browser/assignments.py
M plone/app/contentrules/browser/controlpanel.py
M plone/app/contentrules/browser/elements.py
M plone/app/contentrules/browser/navigation.py
M plone/app/contentrules/browser/resources.py
M plone/app/contentrules/conditions/fileextension.py
M plone/app/contentrules/conditions/portaltype.py
M plone/app/contentrules/exportimport/rules.py
M plone/app/contentrules/handlers.py
M plone/app/contentrules/namechooser.py
M plone/app/contentrules/tests/assignment.txt
M plone/app/contentrules/tests/base.py
M plone/app/contentrules/tests/multipublish.txt
M plone/app/contentrules/tests/simplepublish.txt
M plone/app/contentrules/tests/test_action_copy.py
M plone/app/contentrules/tests/test_action_delete.py
M plone/app/contentrules/tests/test_action_logger.py
M plone/app/contentrules/tests/test_action_mail.py
M plone/app/contentrules/tests/test_action_modify.py
M plone/app/contentrules/tests/test_action_move.py
M plone/app/contentrules/tests/test_action_notify.py
M plone/app/contentrules/tests/test_action_workflow.py
M plone/app/contentrules/tests/test_browser.py
M plone/app/contentrules/tests/test_cascading_rule.py
M plone/app/contentrules/tests/test_condition_group.py
M plone/app/contentrules/tests/test_condition_portal_type.py
M plone/app/contentrules/tests/test_condition_role.py
M plone/app/contentrules/tests/test_condition_tales_expression.py
M plone/app/contentrules/tests/test_condition_wfstate.py
M plone/app/contentrules/tests/test_condition_wftransition.py
M plone/app/contentrules/tests/test_configuration.py
M plone/app/contentrules/tests/test_events.py
M plone/app/contentrules/tests/test_handlers.py
M plone/app/contentrules/tests/test_rule_assignment_mapping.py
M plone/app/contentrules/tests/test_rule_management_views.py
M plone/app/contentrules/tests/test_setup.py
M plone/app/contentrules/tests/test_traversal.py
M setup.py

diff --git a/.gitignore b/.gitignore
index 0cf7321..4decf05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,13 @@
 *.egg-info
-*.pyc
-*.pyo
+*.py[co]
+*.mo
 build
 dist
 .project
 .pydevproject
 .settings
+.installed.cfg
+/bin
+/develop-eggs
+/parts
+*.bak
diff --git a/CHANGES.rst b/CHANGES.rst
index c630d1b..21566d4 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,7 +4,8 @@ Changelog
 3.0.8 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Ported tests to plone.app.testing
+  [tomgross]
 
 
 3.0.7 (2014-04-13)
diff --git a/bootstrap.py b/bootstrap.py
new file mode 100644
index 0000000..ed57894
--- /dev/null
+++ b/bootstrap.py
@@ -0,0 +1,178 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --find-links to point to local resources, you can keep 
+this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
+                  help=("Specify the path to the buildout configuration "
+                        "file to be used."))
+parser.add_option("-f", "--find-links",
+                  help=("Specify a URL to search for buildout releases"))
+parser.add_option("--allow-site-packages",
+                  action="store_true", default=False,
+                  help=("Let bootstrap.py use existing site packages"))
+
+
+options, args = parser.parse_args()
+
+######################################################################
+# load/install setuptools
+
+try:
+    if options.allow_site_packages:
+        import setuptools
+        import pkg_resources
+    from urllib.request import urlopen
+except ImportError:
+    from urllib2 import urlopen
+
+ez = {}
+exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
+
+if not options.allow_site_packages:
+    # ez_setup imports site, which adds site packages
+    # this will remove them from the path to ensure that incompatible versions 
+    # of setuptools are not in the path
+    import site
+    # inside a virtualenv, there is no 'getsitepackages'. 
+    # We can't remove these reliably
+    if hasattr(site, 'getsitepackages'):
+        for sitepackage_path in site.getsitepackages():
+            sys.path[:] = [x for x in sys.path if sitepackage_path not in x]
+
+setup_args = dict(to_dir=tmpeggs, download_delay=0)
+ez['use_setuptools'](**setup_args)
+import setuptools
+import pkg_resources
+
+# This does not (always?) update the default working set.  We will
+# do it.
+for path in sys.path:
+    if path not in pkg_resources.working_set.entries:
+        pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
+ws = pkg_resources.working_set
+
+cmd = [sys.executable, '-c',
+       'from setuptools.command.easy_install import main; main()',
+       '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+    'bootstrap-testing-find-links',
+    options.find_links or
+    ('http://downloads.buildout.org/'
+     if options.accept_buildout_test_releases else None)
+    )
+if find_links:
+    cmd.extend(['-f', find_links])
+
+setuptools_path = ws.find(
+    pkg_resources.Requirement.parse('setuptools')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[setuptools_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
+    raise Exception(
+        "Failed to execute command:\n%s" % repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
+ws.add_entry(tmpeggs)
+ws.require(requirement)
+import zc.buildout.buildout
+
+if not [a for a in args if '=' not in a]:
+    args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args[0:0] = ['-c', options.config_file]
+
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
diff --git a/buildout.cfg b/buildout.cfg
new file mode 100644
index 0000000..56c4146
--- /dev/null
+++ b/buildout.cfg
@@ -0,0 +1,7 @@
+[buildout]
+extends = https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.x.cfg
+package-name = plone.app.contentrules
+package-extras = [test]
+
+[versions]
+plone.app.contentrules = 
diff --git a/plone/app/contentrules/actions/logger.py b/plone/app/contentrules/actions/logger.py
index 059b1f4..c6083f0 100644
--- a/plone/app/contentrules/actions/logger.py
+++ b/plone/app/contentrules/actions/logger.py
@@ -14,7 +14,6 @@
 from plone.app.contentrules import PloneMessageFactory as _
 from plone.app.contentrules.browser.formhelper import AddForm, EditForm
 
-
 logger = logging.getLogger("plone.contentrules.logger")
 handler = logging.StreamHandler()
 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s -  %(message)s")
@@ -32,7 +31,7 @@ class ILoggerAction(Interface):
                                     default='Plone')
 
     loggingLevel = schema.Int(title=_(u'Logging level'),
-                              default=20) # INFO
+                              default=20)  # INFO
 
     message = schema.TextLine(title=_(u"Message"),
                               description=_('help_contentrules_logger_message',
diff --git a/plone/app/contentrules/actions/mail.py b/plone/app/contentrules/actions/mail.py
index d25dbac..5cde935 100644
--- a/plone/app/contentrules/actions/mail.py
+++ b/plone/app/contentrules/actions/mail.py
@@ -21,7 +21,6 @@
 from plone.app.contentrules import PloneMessageFactory as _
 from plone.app.contentrules.browser.formhelper import AddForm, EditForm
 
-
 logger = logging.getLogger("plone.contentrules")
 
 
@@ -118,7 +117,7 @@ def __call__(self):
             source = '"%s" <%s>' % (from_name, from_address)
 
         recip_string = interpolator(self.element.recipients)
-        if recip_string: # check recipient is not None or empty string
+        if recip_string:  # check recipient is not None or empty string
             recipients = set([str(mail.strip()) for mail in recip_string.split(',') \
                               if mail.strip()])
         else:
diff --git a/plone/app/contentrules/api.py b/plone/app/contentrules/api.py
index d6612a7..d9f7bc3 100644
--- a/plone/app/contentrules/api.py
+++ b/plone/app/contentrules/api.py
@@ -1,6 +1,6 @@
 from zope.component import queryUtility
 from plone.contentrules.engine.assignments import RuleAssignment
-from plone.contentrules.engine.interfaces import IRuleStorage,\
+from plone.contentrules.engine.interfaces import IRuleStorage, \
     IRuleAssignmentManager
 from plone.app.contentrules.rule import get_assignments, insert_assignment
 
diff --git a/plone/app/contentrules/browser/assignments.py b/plone/app/contentrules/browser/assignments.py
index b255c0d..c96d4eb 100644
--- a/plone/app/contentrules/browser/assignments.py
+++ b/plone/app/contentrules/browser/assignments.py
@@ -34,14 +34,14 @@ def __call__(self):
             keys = list(assignable.keys())
             idx = keys.index(rule_id)
             del keys[idx]
-            keys.insert(idx-1, rule_id)
+            keys.insert(idx - 1, rule_id)
             assignable.updateOrder(keys)
         elif operation == 'move_down':
             rule_id = request.get('rule_id')
             keys = list(assignable.keys())
             idx = keys.index(rule_id)
             del keys[idx]
-            keys.insert(idx+1, rule_id)
+            keys.insert(idx + 1, rule_id)
             assignable.updateOrder(keys)
         elif 'form.button.AddAssignment' in form:
             rule_id = form.get('rule_id')
@@ -115,12 +115,12 @@ def acquired_rules(self):
                     if key not in in_use and assignment.bubbles:
                         rule = storage.get(key, None)
                         if rule is not None:
-                            assignments.append(dict(id = key,
-                                                    title = rule.title,
-                                                    description = rule.description,
-                                                    trigger = events.get(rule.event, "Unknown"),
-                                                    url = context.absolute_url() + '/@@manage-content-rules',
-                                                    enabled = (assignment.enabled and rule.enabled), ))
+                            assignments.append(dict(id=key,
+                                                    title=rule.title,
+                                                    description=rule.description,
+                                                    trigger=events.get(rule.event, "Unknown"),
+                                                    url=context.absolute_url() + '/@@manage-content-rules',
+                                                    enabled=(assignment.enabled and rule.enabled), ))
             if ISiteRoot.providedBy(context):
                 context = None
             else:
@@ -138,14 +138,14 @@ def assigned_rules(self):
         for key, assignment in assignable.items():
             rule = storage.get(key, None)
             if rule is not None:
-                assignments.append(dict(id = key,
-                                        title = rule.title,
-                                        description = rule.description,
-                                        trigger = events.get(rule.event, "Unknown"),
-                                        url = self._rule_url(key),
-                                        bubbles = assignment.bubbles,
-                                        enabled = assignment.enabled,
-                                        global_enabled = rule.enabled, ))
+                assignments.append(dict(id=key,
+                                        title=rule.title,
+                                        description=rule.description,
+                                        trigger=events.get(rule.event, "Unknown"),
+                                        url=self._rule_url(key),
+                                        bubbles=assignment.bubbles,
+                                        enabled=assignment.enabled,
+                                        global_enabled=rule.enabled, ))
         return assignments
 
     def has_rules(self):
@@ -156,9 +156,9 @@ def assignable_rules(self):
         assignable = []
         for key, rule in getUtility(IRuleStorage).items():
             if key not in in_use:
-                assignable.append(dict(id = key,
-                                       title = rule.title,
-                                       description = rule.description, ))
+                assignable.append(dict(id=key,
+                                       title=rule.title,
+                                       description=rule.description, ))
         return assignable
 
     @memoize
diff --git a/plone/app/contentrules/browser/controlpanel.py b/plone/app/contentrules/browser/controlpanel.py
index bbdf443..0a3aaa3 100644
--- a/plone/app/contentrules/browser/controlpanel.py
+++ b/plone/app/contentrules/browser/controlpanel.py
@@ -15,6 +15,7 @@
 from plone.app.contentrules.rule import get_assignments
 from Products.statusmessages.interfaces import IStatusMessage
 
+
 def get_trigger_class(trigger):
     return "trigger-%s" % trigger.__identifier__.split('.')[-1].lower()
 
diff --git a/plone/app/contentrules/browser/elements.py b/plone/app/contentrules/browser/elements.py
index f7f6c8f..b125b0a 100644
--- a/plone/app/contentrules/browser/elements.py
+++ b/plone/app/contentrules/browser/elements.py
@@ -102,7 +102,7 @@ def rule_event(self):
             if e.value == self.context.event:
                 return translate(e.token, context=self.request, domain='plone')
 
-        return "Unknown event" # should not happen
+        return "Unknown event"  # should not happen
 
     @memoize
     def actions(self):
@@ -196,13 +196,13 @@ def _populate_info(self, elements, meta, namespace):
                 editview = '%s/++%s++%d/%s' % (base_url, namespace, idx,
                                                descriptor.editview, )
 
-            info.append({'title'      : descriptor.title,
+            info.append({'title': descriptor.title,
                          'description': descriptor.description,
-                         'summary'    : data.summary,
-                         'editview'   : editview,
-                         'first'      : (idx == 0),
-                         'last'       : (idx == last),
-                         'idx'        : idx,
+                         'summary': data.summary,
+                         'editview': editview,
+                         'first': (idx == 0),
+                         'last': (idx == last),
+                         'idx': idx,
                         })
         return info
 
diff --git a/plone/app/contentrules/browser/navigation.py b/plone/app/contentrules/browser/navigation.py
index 7fb11ab..d1e18a4 100644
--- a/plone/app/contentrules/browser/navigation.py
+++ b/plone/app/contentrules/browser/navigation.py
@@ -7,7 +7,6 @@
 class RuleBreadcrumbs(PhysicalNavigationBreadcrumbs):
 
     def breadcrumbs(self):
-        base = super(RuleBreadcrumbs, self).breadcrumbs()
         portal_url = getToolByName(self.context, 'portal_url')()
         return ({'absolute_url': '%s/@@rules-controlpanel' % portal_url,
                  'Title': PloneMessageFactory('title_manage_contentrules', default=u"Content rules")},
diff --git a/plone/app/contentrules/browser/resources.py b/plone/app/contentrules/browser/resources.py
index c01df75..1a37d42 100644
--- a/plone/app/contentrules/browser/resources.py
+++ b/plone/app/contentrules/browser/resources.py
@@ -5,4 +5,4 @@ class Resources(ViewletBase):
 
     def render(self):
         return u"""
-      """ % {'portal_url': self.site_url}
\ No newline at end of file
+      """ % {'portal_url': self.site_url}
diff --git a/plone/app/contentrules/conditions/fileextension.py b/plone/app/contentrules/conditions/fileextension.py
index 6156b43..036e565 100644
--- a/plone/app/contentrules/conditions/fileextension.py
+++ b/plone/app/contentrules/conditions/fileextension.py
@@ -66,7 +66,7 @@ def __call__(self):
             return False
 
         name = get_filename()
-        extension = name[name.rfind('.')+1:]
+        extension = name[name.rfind('.') + 1:]
         return extension == self.element.file_extension
 
 
diff --git a/plone/app/contentrules/conditions/portaltype.py b/plone/app/contentrules/conditions/portaltype.py
index 54bfdc7..ef8a90b 100644
--- a/plone/app/contentrules/conditions/portaltype.py
+++ b/plone/app/contentrules/conditions/portaltype.py
@@ -71,7 +71,7 @@ def __call__(self):
             # types tool have a getTypeInfo method
             return False
 
-        ti = obj.getTypeInfo() # getTypeInfo can be None
+        ti = obj.getTypeInfo()  # getTypeInfo can be None
         if ti is None:
             return False
         return ti.getId() in self.element.check_types
diff --git a/plone/app/contentrules/exportimport/rules.py b/plone/app/contentrules/exportimport/rules.py
index a2d8e54..c08592b 100644
--- a/plone/app/contentrules/exportimport/rules.py
+++ b/plone/app/contentrules/exportimport/rules.py
@@ -69,8 +69,6 @@ def export_element(self, doc, node):
 
             child = self.export_field(doc, field)
             node.appendChild(child)
-
-
     # Helper methods
 
     def import_node(self, interface, child):
@@ -237,7 +235,6 @@ def _initRules(self, node):
                 rule.enabled = as_bool(child.getAttribute('enabled'), True)
                 rule.stop = as_bool(child.getAttribute('stop-after'))
                 rule.cascading = as_bool(child.getAttribute('cascading'))
-
                 # Aq-wrap to enable complex setters for elements below
                 # to work
 
@@ -323,7 +320,6 @@ def _extractRules(self):
             rule_node.setAttribute('enabled', str(rule.enabled))
             rule_node.setAttribute('stop-after', str(rule.stop))
             rule_node.setAttribute('cascading', str(rule.cascading))
-
             # Aq-wrap so that exporting fields with clever getters or
             # vocabularies will work. We also aq-wrap conditions and
             # actions below.
@@ -360,7 +356,6 @@ def _extractRules(self):
 
             fragment.appendChild(rule_node)
             assignment_paths.update(get_assignments(rule))
-
         # Export assignments last - this is necessary to ensure they
         # are orderd properly
 
@@ -397,7 +392,7 @@ def importRules(context):
         filename = '%s%s' % (importer.name, importer.suffix)
         body = context.readDataFile(filename)
         if body is not None:
-            importer.filename = filename # for error reporting
+            importer.filename = filename  # for error reporting
             importer.body = body
 
 
diff --git a/plone/app/contentrules/handlers.py b/plone/app/contentrules/handlers.py
index d40fb07..4cece16 100644
--- a/plone/app/contentrules/handlers.py
+++ b/plone/app/contentrules/handlers.py
@@ -1,13 +1,12 @@
 import threading
 
 from zope.component import queryUtility
-from zope.container.interfaces import IObjectAddedEvent, IObjectRemovedEvent,\
+from zope.container.interfaces import IObjectAddedEvent, IObjectRemovedEvent, \
     IContainerModifiedEvent
 from zope.interface import Interface
 from zope.component.hooks import getSite
 
 from plone.app.discussion.interfaces import IComment
-from plone.contentrules.rule.interfaces import IRule
 from plone.contentrules.engine.interfaces import IRuleExecutor
 from plone.contentrules.engine.interfaces import IRuleStorage
 from plone.contentrules.engine.interfaces import StopRule
@@ -16,8 +15,6 @@
 from plone.uuid.interfaces import IUUID
 from Products.CMFCore.interfaces import ISiteRoot, IContentish
 from Products.CMFCore.utils import getToolByName
-from Products.ZCTextIndex.interfaces import IZCLexicon
-from AccessControl.userfolder import UserFolder
 
 try:
     from Products.Archetypes.interfaces import IBaseObject
@@ -26,6 +23,8 @@
 except ImportError:
     class IBaseObject(Interface):
         pass
+
+
     class IObjectInitializedEvent(Interface):
         pass
     HAS_ARCHETYPES = False
@@ -140,10 +139,8 @@ def execute(context, event):
     # execute rules again
     rule_filter.in_progress = False
 
-
 # Event handlers
 
-
 def is_portal_factory(context):
     """Find out if the given object is in portal_factory
     """
diff --git a/plone/app/contentrules/namechooser.py b/plone/app/contentrules/namechooser.py
index efa7f43..fc2978b 100644
--- a/plone/app/contentrules/namechooser.py
+++ b/plone/app/contentrules/namechooser.py
@@ -2,7 +2,6 @@
 from zope.container.interfaces import INameChooser
 from zope.interface import implements
 
-
 ATTEMPTS = 100
 
 
diff --git a/plone/app/contentrules/tests/assignment.txt b/plone/app/contentrules/tests/assignment.txt
index bb74bab..95db1d2 100644
--- a/plone/app/contentrules/tests/assignment.txt
+++ b/plone/app/contentrules/tests/assignment.txt
@@ -1,28 +1,26 @@
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
+  >>> portal = layer['portal']
+  >>> if 'news' not in layer['portal']:
+  ...     obj = portal.invokeFactory('Folder', 'news')
+  >>> import transaction
+  >>> transaction.commit()
 
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
 
 Let's visit the control panel and add two content rules. They will be assigned
 at the root of the site. 
 
 First, we add a rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -63,7 +61,7 @@ Now comes the action, we want all news items to be copied into the
 
 A second rule will be added to notify users when a content is added.
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule', index=0).click()
diff --git a/plone/app/contentrules/tests/base.py b/plone/app/contentrules/tests/base.py
index 238aaa4..05a7bdd 100644
--- a/plone/app/contentrules/tests/base.py
+++ b/plone/app/contentrules/tests/base.py
@@ -1,36 +1,26 @@
-"""Base class for integration tests, based on ZopeTestCase and PloneTestCase.
-
-Note that importing this module has various side-effects: it registers a set of
-products with Zope, and it sets up a sandbox Plone site with the appropriate
-products installed.
+"""Base class for integration tests, based on plone.app.testing
 """
 
-# Import PloneTestCase - this registers more products with Zope as a side effect
-from Products.PloneTestCase.PloneTestCase import PloneTestCase
-from Products.PloneTestCase.PloneTestCase import FunctionalTestCase
-from Products.PloneTestCase.PloneTestCase import setupPloneSite
+from plone.app.testing.bbb import PloneTestCase
 from zope.component import getMultiAdapter
 
-# Set up a Plone site - note that the portlets branch of CMFPlone applies
-# a portlets profile.
-setupPloneSite()
-
 
 class ContentRulesTestCase(PloneTestCase):
-    """Base class for integration tests for plone.app.contentrules. This may
-    provide specific set-up and tear-down operations, or provide convenience
-    methods.
+    """Base class for integration tests for plone.app.contentrules.
+    This may provide specific set-up and tear-down operations, or provide
+    convenience methods.
     """
 
     def addAuthToRequest(self):
-        portal = self.portal
-        request = portal.REQUEST
+        portal = self.layer['portal']
+        request = self.layer['request']
         authenticator = getMultiAdapter((portal, request), name=u"authenticator")
         auth = authenticator.authenticator().split('value="')[1].rstrip('"/>')
         request.form['_authenticator'] = auth
 
-class ContentRulesFunctionalTestCase(FunctionalTestCase):
-    """Base class for functional integration tests for plone.app.portlets.
+
+class ContentRulesFunctionalTestCase(PloneTestCase):
+    """Base class for functional integration tests for plone.app.contentrules.
     This may provide specific set-up and tear-down operations, or provide
     convenience methods.
     """
diff --git a/plone/app/contentrules/tests/multipublish.txt b/plone/app/contentrules/tests/multipublish.txt
index e801071..f7325a7 100644
--- a/plone/app/contentrules/tests/multipublish.txt
+++ b/plone/app/contentrules/tests/multipublish.txt
@@ -4,26 +4,19 @@ during the same request.
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
-
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
+  >>> portal = layer['portal']
 
 Let's visit the control panel and add a content rule.  We'll add a
 rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -103,7 +96,7 @@ Now let's publish both simultaneously.
 
 Both news items should have moved into the `news/` folder now:
 
-  >>> browser.open(self.portal.absolute_url() + '/news/folder_listing')
+  >>> browser.open(portal.absolute_url() + '/news/folder_listing')
   >>> 'My news item' in browser.contents
   True
   >>> 'Second news item' in browser.contents
diff --git a/plone/app/contentrules/tests/simplepublish.txt b/plone/app/contentrules/tests/simplepublish.txt
index 45906f8..ae8044e 100644
--- a/plone/app/contentrules/tests/simplepublish.txt
+++ b/plone/app/contentrules/tests/simplepublish.txt
@@ -1,26 +1,24 @@
 Setup
 -----
 
-  >>> from Testing.ZopeTestCase import user_password
+  >>> from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD
+  >>> from plone.testing.z2 import Browser
 
-  # BBB Zope 2.12
-  >>> try:
-  ...     from Testing.testbrowser import Browser
-  ... except ImportError:
-  ...     from Products.Five.testbrowser import Browser
+  >>> portal = layer['portal']
+  >>> if 'news' not in portal:
+  ...     obj = portal.invokeFactory('Folder', 'news')
+  >>> import transaction
+  >>> transaction.commit()
 
-  >>> if 'news' not in self.portal:
-  ...     self.loginAsPortalOwner()
-  ...     obj = self.portal.invokeFactory('Folder', 'news')
-
-  >>> browser = Browser()
+  >>> browser = Browser(layer['app'])
   >>> browser.addHeader('Authorization',
-  ...                   'Basic %s:%s' % ('portal_owner', user_password))
+  ...                   'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
+
 
 Let's visit the control panel and add a content rule.  We'll add a
 rule with a triggering event of `Workflow state changed`:
 
-  >>> browser.open(self.portal.absolute_url())
+  >>> browser.open(portal.absolute_url())
   >>> browser.getLink('Site Setup').click()
   >>> browser.getLink('Content Rules').click()
   >>> browser.getControl('Add content rule').click()
@@ -85,8 +83,8 @@ Let's go back and create the news item now:
 
 The news item should have been copied into the `news/` folder now:
 
-  >>> 'my-news-item' in self.portal.news
+  >>> 'my-news-item' in portal.news
   True
 
-  >>> 'my-news-item' in self.portal
+  >>> 'my-news-item' in portal
   True
diff --git a/plone/app/contentrules/tests/test_action_copy.py b/plone/app/contentrules/tests/test_action_copy.py
index 739150b..d802e97 100644
--- a/plone/app/contentrules/tests/test_action_copy.py
+++ b/plone/app/contentrules/tests/test_action_copy.py
@@ -9,12 +9,11 @@
 from plone.app.contentrules.actions.copy import CopyEditForm
 
 from plone.app.contentrules.rule import Rule
-
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 
-from zope.component.interfaces import IObjectEvent
+from plone.app.testing import TEST_USER_ID
 
-from Products.PloneTestCase.setup import default_user
+from zope.component.interfaces import IObjectEvent
 
 
 class DummyEvent(object):
@@ -29,7 +28,7 @@ class TestCopyAction(ContentRulesTestCase):
     def afterSetUp(self):
         self.loginAsPortalOwner()
         self.portal.invokeFactory('Folder', 'target')
-        self.login(default_user)
+        self.login()
         self.folder.invokeFactory('Document', 'd1')
 
     def testRegistered(self):
@@ -116,7 +115,7 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.folder.target.invokeFactory('Document', 'd1')
 
         e = CopyAction()
-        e.target_folder = '/Members/%s/target' % default_user
+        e.target_folder = '/Members/%s/target' % TEST_USER_ID
 
         ex = getMultiAdapter((self.folder.target, e, DummyEvent(self.folder.d1)), IExecutable)
         self.assertEqual(True, ex())
@@ -124,10 +123,3 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.assertTrue('d1' in self.folder.objectIds())
         self.assertTrue('d1' in self.folder.target.objectIds())
         self.assertTrue('d1.1' in self.folder.target.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestCopyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_delete.py b/plone/app/contentrules/tests/test_action_delete.py
index eb28b35..6d2f608 100644
--- a/plone/app/contentrules/tests/test_action_delete.py
+++ b/plone/app/contentrules/tests/test_action_delete.py
@@ -54,10 +54,3 @@ def testExecute(self):
         self.assertEqual(True, ex())
 
         self.assertFalse('d1' in self.folder.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestDeleteAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_logger.py b/plone/app/contentrules/tests/test_action_logger.py
index 4df16f7..4fd4631 100644
--- a/plone/app/contentrules/tests/test_action_logger.py
+++ b/plone/app/contentrules/tests/test_action_logger.py
@@ -12,6 +12,8 @@
 from plone.app.contentrules.rule import Rule
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
+from plone.app.testing import TEST_USER_ID
+from plone.app.testing import TEST_USER_NAME
 
 
 class DummyEvent(object):
@@ -24,8 +26,6 @@ class DummyObjectEvent(object):
     def __init__(self, obj):
         self.object = obj
 
-    pass
-
 
 class TestLoggerAction(ContentRulesTestCase):
 
@@ -71,7 +71,7 @@ def testProcessedMessage(self):
         self.assertEqual("Test log event", ex.processedMessage())
 
         e.message = "Test log event : &c"
-        self.assertEqual("Test log event : <ATFolder at /plone/Members/test_user_1_>",
+        self.assertEqual("Test log event : <ATFolder at /plone/Members/%s>" % TEST_USER_ID,
                           ex.processedMessage())
 
         e.message = "Test log event : &e"
@@ -79,7 +79,7 @@ def testProcessedMessage(self):
                           ex.processedMessage())
 
         e.message = "Test log event : &u"
-        self.assertEqual("Test log event : test_user_1_", ex.processedMessage())
+        self.assertEqual("Test log event : %s" % TEST_USER_NAME, ex.processedMessage())
 
     def testExecute(self):
         e = LoggerAction()
@@ -87,11 +87,4 @@ def testExecute(self):
         e.loggingLevel = 0
         e.message = "Test log event"
         ex = getMultiAdapter((self.folder, e, DummyEvent()), IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestLoggerAction))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_action_mail.py b/plone/app/contentrules/tests/test_action_mail.py
index 6a8aac3..ffcff67 100644
--- a/plone/app/contentrules/tests/test_action_mail.py
+++ b/plone/app/contentrules/tests/test_action_mail.py
@@ -228,10 +228,3 @@ def testExecuteBadMailHost(self):
         ex = getMultiAdapter((self.folder, e, DummyEvent(self.folder.d1)),
                              IExecutable)
         ex()
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestMailAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_modify.py b/plone/app/contentrules/tests/test_action_modify.py
index 22b5ceb..10cb428 100644
--- a/plone/app/contentrules/tests/test_action_modify.py
+++ b/plone/app/contentrules/tests/test_action_modify.py
@@ -38,10 +38,3 @@ class Content(object):
             __name__ = None
         handlers.modified(ObjectRemovedEvent(Content()))
         self.assertFalse(self.called)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestModifyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_move.py b/plone/app/contentrules/tests/test_action_move.py
index 41f3677..b5a9c60 100644
--- a/plone/app/contentrules/tests/test_action_move.py
+++ b/plone/app/contentrules/tests/test_action_move.py
@@ -14,7 +14,7 @@
 
 from zope.component.interfaces import IObjectEvent
 
-from Products.PloneTestCase.setup import default_user
+from plone.app.testing import TEST_USER_ID as default_user
 
 
 class DummyEvent(object):
@@ -29,7 +29,7 @@ class TestMoveAction(ContentRulesTestCase):
     def afterSetUp(self):
         self.loginAsPortalOwner()
         self.portal.invokeFactory('Folder', 'target')
-        self.login(default_user)
+        self.login()
         self.folder.invokeFactory('Document', 'd1')
 
     def testRegistered(self):
@@ -71,7 +71,7 @@ def testExecute(self):
         self.assertTrue('d1' in self.portal.target.objectIds())
 
         # test catalog is ok
-        brains  = self.portal.portal_catalog(id='d1')
+        brains = self.portal.portal_catalog(id='d1')
         self.assertEqual(len(brains), 1)
         self.assertEqual(brains[0].getPath(), '/plone/target/d1')
 
@@ -142,10 +142,3 @@ def testExecuteWithNamingConflictDoesNotStupidlyAcquireHasKey(self):
         self.assertFalse('d1' in self.folder.objectIds())
         self.assertTrue('d1' in self.folder.target.objectIds())
         self.assertTrue('d1.1' in self.folder.target.objectIds())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestMoveAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_notify.py b/plone/app/contentrules/tests/test_action_notify.py
index f450729..f73a38c 100644
--- a/plone/app/contentrules/tests/test_action_notify.py
+++ b/plone/app/contentrules/tests/test_action_notify.py
@@ -13,7 +13,6 @@
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 
 from Products.statusmessages import STATUSMESSAGEKEY
-from Products.statusmessages.interfaces import IStatusMessage
 from Products.statusmessages.adapter import _decodeCookieValue
 
 
@@ -25,6 +24,7 @@ class TestNotifyAction(ContentRulesTestCase):
 
     def afterSetUp(self):
         self.setRoles(('Manager', ))
+        self.request = self.layer['request']
 
     def testRegistered(self):
         element = getUtility(IRuleAction, name='plone.actions.Notify')
@@ -39,8 +39,8 @@ def testInvokeAddView(self):
         storage[u'foo'] = Rule()
         rule = self.portal.restrictedTraverse('++rule++foo')
 
-        adding = getMultiAdapter((rule, self.portal.REQUEST), name='+action')
-        addview = getMultiAdapter((adding, self.portal.REQUEST), name=element.addview)
+        adding = getMultiAdapter((rule, self.request), name='+action')
+        addview = getMultiAdapter((adding, self.request), name=element.addview)
 
         addview.createAndAdd(data={'message': 'Hello world', 'message_type': 'info'})
 
@@ -52,7 +52,7 @@ def testInvokeAddView(self):
     def testInvokeEditView(self):
         element = getUtility(IRuleAction, name='plone.actions.Notify')
         e = NotifyAction()
-        editview = getMultiAdapter((e, self.folder.REQUEST), name=element.editview)
+        editview = getMultiAdapter((e, self.request), name=element.editview)
         self.assertTrue(isinstance(editview, NotifyEditForm))
 
     def testExecute(self):
@@ -63,16 +63,8 @@ def testExecute(self):
         ex = getMultiAdapter((self.folder, e, DummyEvent()), IExecutable)
         self.assertEqual(True, ex())
 
-        status = IStatusMessage(self.app.REQUEST)
-        new_cookies = self.app.REQUEST.RESPONSE.cookies[STATUSMESSAGEKEY]
+        new_cookies = self.request.RESPONSE.cookies[STATUSMESSAGEKEY]
         messages = _decodeCookieValue(new_cookies['value'])
         self.assertEqual(1, len(messages))
         self.assertEqual('Hello world', messages[0].message)
         self.assertEqual('info', messages[0].type)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestNotifyAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_action_workflow.py b/plone/app/contentrules/tests/test_action_workflow.py
index 0aaa0ff..e55b3c8 100644
--- a/plone/app/contentrules/tests/test_action_workflow.py
+++ b/plone/app/contentrules/tests/test_action_workflow.py
@@ -75,10 +75,3 @@ def testExecuteWithError(self):
         self.assertEqual(False, ex())
 
         self.assertEqual(old_state, self.portal.portal_workflow.getInfoFor(self.folder.d1, 'review_state'))
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowAction))
-    return suite
diff --git a/plone/app/contentrules/tests/test_browser.py b/plone/app/contentrules/tests/test_browser.py
index 14b0cda..e2a4d9f 100644
--- a/plone/app/contentrules/tests/test_browser.py
+++ b/plone/app/contentrules/tests/test_browser.py
@@ -1,22 +1,19 @@
 import unittest
+import doctest
 
-from Testing.ZopeTestCase import FunctionalDocFileSuite as Suite
-from Products.PloneTestCase import PloneTestCase as ptc
-from Products.PloneTestCase.PloneTestCase import setupPloneSite
+from plone.app.testing.bbb import PTC_FUNCTIONAL_TESTING
+from plone.testing import layered
 
-setupPloneSite()
+optionflags = (doctest.NORMALIZE_WHITESPACE |
+               doctest.ELLIPSIS |
+               doctest.REPORT_NDIFF)
 
 
 def test_suite():
-    suites = [
-        Suite('assignment.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase),
-        Suite('simplepublish.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase),
-        Suite('multipublish.txt',
-              package='plone.app.contentrules.tests',
-              test_class=ptc.FunctionalTestCase)]
-
-    return unittest.TestSuite(suites)
+    suite = unittest.TestSuite()
+    for doc in ['assignment.txt', 'simplepublish.txt', 'multipublish.txt']:
+        suite.addTest(layered(
+            doctest.DocFileSuite(doc, package='plone.app.contentrules.tests',
+                                 optionflags=optionflags),
+            layer=PTC_FUNCTIONAL_TESTING))
+    return suite
diff --git a/plone/app/contentrules/tests/test_cascading_rule.py b/plone/app/contentrules/tests/test_cascading_rule.py
index 70ed3d0..4e050a0 100644
--- a/plone/app/contentrules/tests/test_cascading_rule.py
+++ b/plone/app/contentrules/tests/test_cascading_rule.py
@@ -1,29 +1,11 @@
 # -*- coding: utf-8 -*-
-
-import time
-
-from plone.contentrules.engine.interfaces import IRuleAssignmentManager
 from plone.contentrules.engine.interfaces import IRuleStorage
 from zope.component import getUtility
-from zope.component import getMultiAdapter
-from zope.lifecycleevent.interfaces import IObjectModifiedEvent
-
-from Products.GenericSetup.interfaces import IBody
-from Products.GenericSetup.context import TarballExportContext
-from Products.PloneTestCase.layer import PloneSite
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
 from plone.app.contentrules.tests.test_configuration import TestContentrulesGSLayer
 from plone.app.contentrules.api import edit_rule_assignment
 
-# BBB Zope 2.12
-try:
-    from Zope2.App import zcml
-    from OFS import metaconfigure
-except ImportError:
-    from Products.Five import zcml
-    from Products.Five import fiveconfigure as metaconfigure
-
 
 class TestCascadingRule(ContentRulesTestCase):
 
@@ -55,12 +37,5 @@ def test_cascading_rule(self):
         self.assertTrue('my-event' in self.portal.events)
 
         wtool = self.portal.portal_workflow
-        self.assertTrue(wtool.getInfoFor(self.portal.events['my-event'], 'review_state'),
+        self.assertEqual(wtool.getInfoFor(self.portal.events['my-event'], 'review_state'),
                         'published')
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestCascadingRule))
-    return suite
diff --git a/plone/app/contentrules/tests/test_condition_group.py b/plone/app/contentrules/tests/test_condition_group.py
index bd5f4c9..8fbe0fd 100644
--- a/plone/app/contentrules/tests/test_condition_group.py
+++ b/plone/app/contentrules/tests/test_condition_group.py
@@ -60,17 +60,10 @@ def testExecute(self):
         e.group_names = ['Administrators', 'Reviewers']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         group = self.portal.portal_groups.getGroupById('Administrators')
         group.addMember(self.portal.portal_membership.getAuthenticatedMember().getId())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestGroupCondition))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_condition_portal_type.py b/plone/app/contentrules/tests/test_condition_portal_type.py
index 1475fef..de5fa3b 100644
--- a/plone/app/contentrules/tests/test_condition_portal_type.py
+++ b/plone/app/contentrules/tests/test_condition_portal_type.py
@@ -60,18 +60,11 @@ def testExecute(self):
         e.check_types = ['Folder', 'Image']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         self.folder.portal_types = None
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestPortalTypeCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_role.py b/plone/app/contentrules/tests/test_condition_role.py
index 7ee74ac..7343976 100644
--- a/plone/app/contentrules/tests/test_condition_role.py
+++ b/plone/app/contentrules/tests/test_condition_role.py
@@ -60,16 +60,9 @@ def testExecute(self):
         e.role_names = ['Manager', 'Member']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         e.role_names = ['Reviewer']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRoleCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_tales_expression.py b/plone/app/contentrules/tests/test_condition_tales_expression.py
index 332aba4..c04fb83 100644
--- a/plone/app/contentrules/tests/test_condition_tales_expression.py
+++ b/plone/app/contentrules/tests/test_condition_tales_expression.py
@@ -73,10 +73,3 @@ def testExecuteUnicodeString(self):
         e.tales_expression = u'string:${portal_url}'
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
         self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestTalesExpressionCondition))
-    return suite
diff --git a/plone/app/contentrules/tests/test_condition_wfstate.py b/plone/app/contentrules/tests/test_condition_wfstate.py
index cf2a6cd..b70bb57 100644
--- a/plone/app/contentrules/tests/test_condition_wfstate.py
+++ b/plone/app/contentrules/tests/test_condition_wfstate.py
@@ -60,19 +60,12 @@ def testExecute(self):
         e.wf_states = ['visible', 'private']
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         self.portal.portal_workflow.doActionFor(self.folder, 'publish')
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.folder)), IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         ex = getMultiAdapter((self.portal, e, DummyEvent(self.portal)), IExecutable)
-        self.assertEqual(False, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowStateCondition))
-    return suite
+        self.assertFalse(ex())
diff --git a/plone/app/contentrules/tests/test_condition_wftransition.py b/plone/app/contentrules/tests/test_condition_wftransition.py
index 8fbc200..e7ed2f9 100644
--- a/plone/app/contentrules/tests/test_condition_wftransition.py
+++ b/plone/app/contentrules/tests/test_condition_wftransition.py
@@ -55,21 +55,14 @@ def testExecute(self):
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'publish', None)),
                              IExecutable)
-        self.assertEqual(True, ex())
+        self.assertTrue(ex())
 
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'retract', None)),
                              IExecutable)
-        self.assertEqual(False, ex())
+        self.assertFalse(ex())
 
         ex = getMultiAdapter((self.portal, e,
                               ActionSucceededEvent(self.folder, 'dummy_workflow', 'hide', None)),
                              IExecutable)
-        self.assertEqual(True, ex())
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestWorkflowTransitionCondition))
-    return suite
+        self.assertTrue(ex())
diff --git a/plone/app/contentrules/tests/test_configuration.py b/plone/app/contentrules/tests/test_configuration.py
index 8e354d0..f146cff 100644
--- a/plone/app/contentrules/tests/test_configuration.py
+++ b/plone/app/contentrules/tests/test_configuration.py
@@ -10,49 +10,23 @@
 
 from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.context import TarballExportContext
-from Products.PloneTestCase.layer import PloneSite
 
 from plone.app.contentrules.tests.base import ContentRulesTestCase
-
-# BBB Zope 2.12
-try:
-    from Zope2.App import zcml
-    from OFS import metaconfigure
-except ImportError:
-    from Products.Five import zcml
-    from Products.Five import fiveconfigure as metaconfigure
-
-
-zcml_string = """\
-<configure xmlns="http://namespaces.zope.org/zope"
-           xmlns:gs="http://namespaces.zope.org/genericsetup"
-           package="plone.app.contentrules"
-           i18n_domain="plone">
-
-    <gs:registerProfile
-        name="testing"
-        title="plone.app.contentrules testing"
-        description="Used for testing only"
-        directory="tests/profiles/testing"
-        for="Products.CMFCore.interfaces.ISiteRoot"
-        provides="Products.GenericSetup.interfaces.EXTENSION"
-        />
-
-</configure>
-"""
+from plone.app.testing.bbb import PloneTestCaseFixture
+from plone.app.testing import FunctionalTesting
 
 
-class TestContentrulesGSLayer(PloneSite):
+class TestContentrulesGSFixture(PloneTestCaseFixture):
 
-    @classmethod
-    def setUp(cls):
-        metaconfigure.debug_mode = True
-        zcml.load_string(zcml_string)
-        metaconfigure.debug_mode = False
+    def setUpZope(self, app, configurationContext):
+        super(TestContentrulesGSFixture,
+                  self).setUpZope(app, configurationContext)
+        import plone.app.contentrules.tests
+        self.loadZCML('testing.zcml', package=plone.app.contentrules.tests)
 
-    @classmethod
-    def tearDown(cls):
-        pass
+ContentrulesGSFixture = TestContentrulesGSFixture()
+TestContentrulesGSLayer = FunctionalTesting(bases=(ContentrulesGSFixture, ),
+                                            name='TestContentRules:Functional')
 
 
 class TestGenericSetup(ContentRulesTestCase):
@@ -127,7 +101,7 @@ def testImportTwice(self):
         # Ensure rules, actions/conditions and assignments are not duplicated
         # if the profile is re-imported; see bug #8027.
         portal_setup = self.portal.portal_setup
-        time.sleep(1) # avoid timestamp colission
+        time.sleep(1)  # avoid timestamp colission
         portal_setup.runAllImportStepsFromProfile('profile-plone.app.contentrules:testing')
 
         # We should get the same results as before
@@ -239,10 +213,3 @@ def testExport(self):
 
         body = exporter.body
         self.assertEqual(expected.strip(), body.strip(), body)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestGenericSetup))
-    return suite
diff --git a/plone/app/contentrules/tests/test_events.py b/plone/app/contentrules/tests/test_events.py
index e7ac471..c4a677a 100644
--- a/plone/app/contentrules/tests/test_events.py
+++ b/plone/app/contentrules/tests/test_events.py
@@ -10,10 +10,3 @@ def testEventHandlerExecutesRules(self):
     def testEventHandlerExecutesRulesOnlyOnce(self):
         # XXX Test missing
         pass
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestEvents))
-    return suite
diff --git a/plone/app/contentrules/tests/test_handlers.py b/plone/app/contentrules/tests/test_handlers.py
index b9fa8cd..99460fe 100644
--- a/plone/app/contentrules/tests/test_handlers.py
+++ b/plone/app/contentrules/tests/test_handlers.py
@@ -54,10 +54,3 @@ def test_delayed_events(self):
         handlers.added(event2)
         from plone.app.contentrules.handlers import _status
         self.assertEqual(len(_status.delayed_events), 2)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestDuplicateRuleFilter))
-    return suite
diff --git a/plone/app/contentrules/tests/test_rule_assignment_mapping.py b/plone/app/contentrules/tests/test_rule_assignment_mapping.py
index 8f956bc..952dfd3 100644
--- a/plone/app/contentrules/tests/test_rule_assignment_mapping.py
+++ b/plone/app/contentrules/tests/test_rule_assignment_mapping.py
@@ -127,10 +127,3 @@ def testRuleAssignmentAddedAPI(self):
         self.assertFalse(self.f11a['r3'].bubbles)
 
         self.assertEqual(self.f11a.keys(), ['r1', 'r3', 'r2'])
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRuleAssignmentMapping))
-    return suite
diff --git a/plone/app/contentrules/tests/test_rule_management_views.py b/plone/app/contentrules/tests/test_rule_management_views.py
index 8be252e..5df6cc1 100644
--- a/plone/app/contentrules/tests/test_rule_management_views.py
+++ b/plone/app/contentrules/tests/test_rule_management_views.py
@@ -138,7 +138,6 @@ def testRulesControlPanel(self):
         registered_rules = controlpanel.registeredRules()
         self.assertEqual(0, len(registered_rules))
 
-
     def testChangeGloballyEnable(self):
         storage = getUtility(IRuleStorage)
         portal = self.portal
@@ -155,10 +154,3 @@ def testChangeGloballyEnable(self):
 
         # without ajax
         self.portal.REQUEST.form
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestRuleManagementViews))
-    suite.addTest(makeSuite(TestRuleElementManagementViews))
-    return suite
diff --git a/plone/app/contentrules/tests/test_setup.py b/plone/app/contentrules/tests/test_setup.py
index f665051..6461322 100644
--- a/plone/app/contentrules/tests/test_setup.py
+++ b/plone/app/contentrules/tests/test_setup.py
@@ -18,10 +18,3 @@ def testEventTypesMarked(self):
         self.assertTrue(IRuleEventType.providedBy(IObjectAddedEvent))
         self.assertTrue(IRuleEventType.providedBy(IObjectModifiedEvent))
         self.assertTrue(IRuleEventType.providedBy(IObjectRemovedEvent))
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestProductInstall))
-    return suite
diff --git a/plone/app/contentrules/tests/test_traversal.py b/plone/app/contentrules/tests/test_traversal.py
index 0bfe975..a91e4d9 100644
--- a/plone/app/contentrules/tests/test_traversal.py
+++ b/plone/app/contentrules/tests/test_traversal.py
@@ -68,10 +68,3 @@ def testTraverseToRuleAction(self):
 
         self.assertTrue(aq_parent(te2) is tr)
         self.assertEqual("y", te2.x)
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestTraversal))
-    return suite
diff --git a/plone/app/contentrules/tests/testing.zcml b/plone/app/contentrules/tests/testing.zcml
new file mode 100644
index 0000000..80dcd4d
--- /dev/null
+++ b/plone/app/contentrules/tests/testing.zcml
@@ -0,0 +1,15 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:gs="http://namespaces.zope.org/genericsetup"
+           package="plone.app.contentrules"
+           i18n_domain="plone">
+
+    <gs:registerProfile
+        name="testing"
+        title="plone.app.contentrules testing"
+        description="Used for testing only"
+        directory="tests/profiles/testing"
+        for="Products.CMFCore.interfaces.ISiteRoot"
+        provides="Products.GenericSetup.interfaces.EXTENSION"
+        />
+
+</configure>
diff --git a/setup.py b/setup.py
index 9aa30ab..80a27ad 100644
--- a/setup.py
+++ b/setup.py
@@ -10,10 +10,12 @@
       classifiers=[
           "Environment :: Web Environment",
           "Framework :: Plone",
+          "Framework :: Plone :: 5.0",
           "Framework :: Zope2",
           "License :: OSI Approved :: GNU General Public License (GPL)",
           "Operating System :: OS Independent",
           "Programming Language :: Python",
+          "Programming Language :: Python :: 2.7",
         ],
       keywords='',
       author='Plone Foundation',
@@ -24,7 +26,7 @@
       namespace_packages = ['plone', 'plone.app'],
       include_package_data=True,
       zip_safe=False,
-      extras_require={'test': 'Products.PloneTestCase'},
+      extras_require={'test': 'plone.app.testing'},
       install_requires=[
         'setuptools',
         'five.formlib',




-------------------------------------------------------------------------------
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CHANGES.log
Type: application/octet-stream
Size: 128319 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140718/906b83c1/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: build.log
Type: application/octet-stream
Size: 262132 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140718/906b83c1/attachment-0003.obj>


More information about the Testbot mailing list