Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into dx-siteroot
Browse files Browse the repository at this point in the history
  • Loading branch information
jaroel committed Feb 24, 2020
2 parents 0078a52 + e6e31a9 commit 6983805
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 35 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ matrix:
env: TOXENV=lint-py27
- python: "3.6"
env: TOXENV=lint-py36
- python: "3.7"
env: TOXENV=lint-py37
- python: "3.8"
env: TOXENV=lint-py38
- python: "2.7"
env: TOXENV=py27
- python: "3.5"
env: TOXENV=py35
- python: "3.6"
env: TOXENV=py36
- python: "3.7"
env: TOXENV=py37
- python: "3.8"
env: TOXENV=py38

install:
- travis_retry pip install -U tox coveralls coverage
Expand Down
3 changes: 0 additions & 3 deletions buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ develop = .
[versions]
plone.app.testing =

[sources]
plone.testing = git ${remotes:plone}/plone.testing.git pushurl=${remotes:plone_push}/plone.testing.git branch=py3_disallow_commits

[test]
recipe = zc.recipe.testrunner
eggs =
Expand Down
1 change: 1 addition & 0 deletions news/61.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a test isolation issue that was preventing the MOCK_MAILHOST_FIXTURE to be used in multiple testcases [ale-rt]
1 change: 1 addition & 0 deletions news/62.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MockMailHostLayer configures the mail sender setting the appropriate registry records (Fixes #62)
2 changes: 2 additions & 0 deletions news/68.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix tests when using zope.testrunner internals since its version 5.1.
[jensens]
8 changes: 4 additions & 4 deletions src/plone/app/testing/helpers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ We'll now tear down just the ``HELPER_DEMOS_INTEGRATION_TESTING`` layer. At this
point, we should still have a Plone site, but none of the persistent or
component architecture changes from our layer.

>>> runner.tear_down_unneeded(options, [l for l in setupLayers if l not in (HELPER_DEMOS_INTEGRATION_TESTING, HELPER_DEMOS_FIXTURE,)], setupLayers)
>>> runner.tear_down_unneeded(options, [l for l in setupLayers if l not in (HELPER_DEMOS_INTEGRATION_TESTING, HELPER_DEMOS_FIXTURE,)], setupLayers, [])
Tear down plone.app.testing.layers.HelperDemos:Integration in ... seconds.
Tear down...HelperDemos in ... seconds.

Expand All @@ -254,7 +254,7 @@ component architecture changes from our layer.

Let's tear down the rest of the layers too.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Tear down plone.testing.zca.LayerCleanup in ... seconds.
Expand Down Expand Up @@ -397,7 +397,7 @@ We'll now tear down just the ``MY_INTEGRATION_TESTING`` layer. At this
point, we should still have a Plone site, but none of the changes from our
layer.

>>> runner.tear_down_unneeded(options, [l for l in setupLayers if l not in (MY_INTEGRATION_TESTING, MY_FIXTURE)], setupLayers)
>>> runner.tear_down_unneeded(options, [l for l in setupLayers if l not in (MY_INTEGRATION_TESTING, MY_FIXTURE)], setupLayers, [])
Tear down plone.app.testing.layers.MyLayer:Integration in ... seconds.

>>> queryUtility(Interface, name="dummy1") is None
Expand Down Expand Up @@ -436,7 +436,7 @@ layer.

Let's tear down the rest of the layers too.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Tear down plone.testing.zca.LayerCleanup in ... seconds.
Expand Down
47 changes: 33 additions & 14 deletions src/plone/app/testing/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
from plone.app.testing.interfaces import TEST_USER_PASSWORD
from plone.app.testing.interfaces import TEST_USER_ROLES
from plone.app.testing.utils import MockMailHost
from plone.registry.interfaces import IRegistry
from plone.testing import Layer
from plone.testing import zca
from plone.testing import zodb
from plone.testing import zope
from plone.testing import zserver
from Products.MailHost.interfaces import IMailHost
from zope.component import getSiteManager
from zope.component import getUtility
from zope.component.hooks import setSite
from zope.event import notify
from zope.traversing.interfaces import BeforeTraverseEvent
Expand Down Expand Up @@ -381,30 +383,47 @@ class MockMailHostLayer(Layer):
"""
defaultBases = (PLONE_FIXTURE,)

def setUp(self):
def testSetUp(self):
with zope.zopeApp() as app:
portal = app[PLONE_SITE_ID]
portal.email_from_address = 'noreply@example.com'
portal.email_from_name = 'Plone Site'
registry = getUtility(IRegistry, context=portal)

if not registry["plone.email_from_address"]:
portal._original_email_address = registry["plone.email_from_address"] # noqa: E501
registry["plone.email_from_address"] = "noreply@example.com"

if not registry["plone.email_from_name"]:
portal._original_email_name = registry["plone.email_from_name"]
registry["plone.email_from_name"] = u"Plone site"

portal._original_MailHost = portal.MailHost
portal.MailHost = mailhost = MockMailHost('MailHost')
portal.MailHost.smtp_host = 'localhost'

sm = getSiteManager(context=portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(mailhost, provided=IMailHost)

def tearDown(self):
def testTearDown(self):

with zope.zopeApp() as app:
portal = app[PLONE_SITE_ID]
_o_mailhost = getattr(portal, '_original_MailHost', None)
if _o_mailhost:
portal.MailHost = portal._original_MailHost
sm = getSiteManager(context=portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(
aq_base(portal._original_MailHost),
provided=IMailHost
)
registry = getUtility(IRegistry, context=portal)

portal.MailHost = portal._original_MailHost

sm = getSiteManager(context=portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(aq_base(portal.MailHost), provided=IMailHost)

if hasattr(portal, "_original_email_name"):
registry["plone.email_from_name"] = portal._original_email_name
delattr(portal, "_original_email_name")

if hasattr(portal, "_original_email_address"):
registry["plone.email_from_address"] = portal._original_email_address # noqa: E501
delattr(portal, "_original_email_address")

delattr(portal, "_original_MailHost")


MOCK_MAILHOST_FIXTURE = MockMailHostLayer()
Expand Down
106 changes: 102 additions & 4 deletions src/plone/app/testing/layers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ There is no default workflow or content:

Layer tear-down resets the environment.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Tear down plone.testing.zca.LayerCleanup in ... seconds.
Expand Down Expand Up @@ -186,7 +186,7 @@ And the component site has been reset:

Layer tear-down resets the environment.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.Plone:Integration in ... seconds.
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Expand Down Expand Up @@ -266,7 +266,7 @@ Along with the rest of the state:

Layer tear-down resets the environment.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.Plone:Functional in ... seconds.
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Expand Down Expand Up @@ -367,7 +367,7 @@ Test tear-down does nothing beyond what the base layers do.

When the server is torn down, the ZServer thread is stopped.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.Plone:WSGIServer in ... seconds.
Tear down plone.testing.zope.WSGIServer in ... seconds.
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Expand All @@ -379,3 +379,101 @@ When the server is torn down, the ZServer thread is stopped.
Traceback (most recent call last):
...
requests.exceptions.ConnectionError: ...


Mock MailHost
~~~~~~~~~~~~~

The fixture ``MOCK_MAILHOST_FIXTURE`` layer
allows to replace the Zope MailHost with a dummy one.

**Note:** This layer builds on top of ``PLONE_FIXTURE``.
Like ``PLONE_FIXTURE``, it should only be used as a base layer,
and not directly in tests.
See this package's ``README`` file for details.

>>> layers.MOCK_MAILHOST_FIXTURE.__bases__
(<Layer 'plone.app.testing.layers.PloneFixture'>,)
>>> options = runner.get_options([], [])
>>> setupLayers = {}
>>> runner.setup_layer(options, layers.MOCK_MAILHOST_FIXTURE, setupLayers)
Set up plone.testing.zca.LayerCleanup in ... seconds.
Set up plone.testing.zope.Startup in ... seconds.
Set up plone.app.testing.layers.PloneFixture in ... seconds.
Set up plone.app.testing.layers.MockMailHostLayer in ... seconds.

Let's now simulate a test.
Test setup sets a couple of registry records and
replaces the mail host with a dummy one:

>>> from zope.component import getUtility
>>> from plone.registry.interfaces import IRegistry

>>> zca.LAYER_CLEANUP.testSetUp()
>>> zope.STARTUP.testSetUp()
>>> layers.MOCK_MAILHOST_FIXTURE.testSetUp()

>>> with helpers.ploneSite() as portal:
... registry = getUtility(IRegistry, context=portal)

>>> registry["plone.email_from_address"]
'noreply@example.com'
>>> registry["plone.email_from_name"]
'Plone site'

The dummy MailHost, instead of sending the emails,
stores them in a list of messages:

>>> with helpers.ploneSite() as portal:
... portal.MailHost.messages
[]

If we send a message, we can check it in the list:

>>> with helpers.ploneSite() as portal:
... portal.MailHost.send(
... "Hello world!",
... mto="foo@example.com",
... mfrom="bar@example.com",
... subject="Test",
... msg_type="text/plain",
... )
>>> with helpers.ploneSite() as portal:
... for message in portal.MailHost.messages:
... print(message)
MIME-Version: 1.0
Content-Type: text/plain
Subject: Test
To: foo@example.com
From: bar@example.com
Date: ...
<BLANKLINE>
Hello world!

The list can be reset:

>>> with helpers.ploneSite() as portal:
... portal.MailHost.reset()
... portal.MailHost.messages
[]

When the test is torn down the original MaiHost is restored
and the registry is cleaned up:

>>> layers.MOCK_MAILHOST_FIXTURE.testTearDown()
>>> zope.STARTUP.testTearDown()
>>> zca.LAYER_CLEANUP.testTearDown()

>>> with helpers.ploneSite() as portal:
... portal.MailHost.messages
Traceback (most recent call last):
...
AttributeError: 'RequestContainer' object has no attribute 'messages'

>>> registry["plone.email_from_address"]
>>> registry["plone.email_from_name"]
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.MockMailHostLayer in ... seconds.
Tear down plone.app.testing.layers.PloneFixture in ... seconds.
Tear down plone.testing.zope.Startup in ... seconds.
Tear down plone.testing.zca.LayerCleanup in ... seconds.
2 changes: 1 addition & 1 deletion src/plone/app/testing/layers_zserver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Test tear-down does nothing beyond what the base layers do.

When the server is torn down, the FTP server thread is stopped.

>>> runner.tear_down_unneeded(options, [], setupLayers)
>>> runner.tear_down_unneeded(options, [], setupLayers, [])
Tear down plone.app.testing.layers.Plone:FTPServer in ... seconds.
Tear down plone.testing.zserver.FTPServer in ... seconds.
Tear down plone.app.testing.layers.PloneZServerFixture in ... seconds.
Expand Down
33 changes: 27 additions & 6 deletions src/plone/app/testing/tests.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import doctest
import re
import six
import unittest

Expand All @@ -12,18 +13,38 @@ def dummy(context):
pass


class Py23DocChecker(doctest.OutputChecker):
def check_output(self, want, got, optionflags):
if six.PY2:
got = re.sub("u'(.*?)'", "'\\1'", got)
return doctest.OutputChecker.check_output(self, want, got, optionflags)


def test_suite():
suite = unittest.TestSuite()
# seltest = doctest.DocFileSuite('selenium.rst', optionflags=OPTIONFLAGS)
# Run selenium tests on level 2, as it requires a correctly configured
# Firefox browser
# seltest.level = 2
suite.addTests([
doctest.DocFileSuite('cleanup.rst', optionflags=OPTIONFLAGS),
doctest.DocFileSuite('layers.rst', optionflags=OPTIONFLAGS),
doctest.DocFileSuite('helpers.rst', optionflags=OPTIONFLAGS),
# seltest,
])
suite.addTests(
[
doctest.DocFileSuite(
"cleanup.rst",
optionflags=OPTIONFLAGS,
checker=Py23DocChecker(),
),
doctest.DocFileSuite(
"layers.rst",
optionflags=OPTIONFLAGS,
checker=Py23DocChecker(),
),
doctest.DocFileSuite(
"helpers.rst",
optionflags=OPTIONFLAGS,
checker=Py23DocChecker(),
),
]
)
if six.PY2:
suite.addTests([
doctest.DocFileSuite(
Expand Down
11 changes: 10 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ envlist =
py27,
py36,
py37,
py38,
coverage-report,
docs,
lint-py27,
lint-py36,
lint-py37,
lint-py38,

minversion = 1.9

Expand Down Expand Up @@ -115,7 +117,14 @@ commands = {[lint]commands}
whitelist_externals = {[lint]whitelist_externals}

[testenv:lint-py37]
basepython = python3.6
basepython = python3.7
skip_install = true
deps = {[lint]deps}
commands = {[lint]commands}
whitelist_externals = {[lint]whitelist_externals}

[testenv:lint-py38]
basepython = python3.8
skip_install = true
deps = {[lint]deps}
commands = {[lint]commands}
Expand Down

0 comments on commit 6983805

Please sign in to comment.