launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #08552
[Merge] lp:~bac/launchpad/bug-682772 into lp:launchpad
Brad Crittenden has proposed merging lp:~bac/launchpad/bug-682772 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #682772 in Launchpad itself: "doctest construction generates duplicate test ids"
https://bugs.launchpad.net/launchpad/+bug/682772
For more details, see:
https://code.launchpad.net/~bac/launchpad/bug-682772/+merge/108983
= Summary =
Correct doctests that are reused with the same id.
Fix the LayeredDoctFileSuite factory to accept another parameter that
is used to augment the filenames into new ids in order to make them
unique.
Note that nothing currently ensure the tests are unique as it is a
volunteer effort. See the companion bug 682771 for that effort.
Also fixed a pair of unit tests that were run multiple times due to
the base class being discovered upon import.
== Pre-implementation notes ==
Talks with Gary.
== Implementation details ==
As above.
== Tests ==
== Demo and Q/A ==
Downloading this file http://pastebin.ubuntu.com/1027090/ as
finddups.py, run...
bin/test --list > list.out; python finddups.py > dups.txt
...and ensure there are not dupes. Well, there is the
twisted/.../runTest dupe but that one is being ignored as beyond the
scope of this change.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/bugs/tests/test_bugtarget.py
lib/lp/testing/pages.py
lib/lp/registry/tests/test_distroseries.py
lib/lp/answers/tests/test_doc.py
versions.cfg
lib/lp/soyuz/tests/test_doc.py
lib/lp/bugs/tests/test_buglinktarget.py
lib/lp/bugs/tests/test_doc.py
lib/lp/registry/tests/test_doc.py
lib/lp/bugs/tests/test_structuralsubscriptiontarget.py
lib/lp/testing/systemdocs.py
lib/lp/services/webservice/tests/test_doc.py
lib/lp/coop/answersbugs/tests/test_doc.py
lib/lp/registry/tests/test_distribution.py
lib/lp/testing/tests/test_inlinetests.py
lib/lp/bugs/tests/test_bugcontact.py
--
https://code.launchpad.net/~bac/launchpad/bug-682772/+merge/108983
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/launchpad/bug-682772 into lp:launchpad.
=== modified file 'lib/lp/answers/tests/test_doc.py'
--- lib/lp/answers/tests/test_doc.py 2012-01-01 02:58:52 +0000
+++ lib/lp/answers/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -87,10 +87,13 @@
suite = unittest.TestSuite()
for name, setup_func in targets:
+ test_path = os.path.join(os.path.pardir, 'doc', test_file)
+ id_ext = "%s-%s" % (test_file, name)
test = LayeredDocFileSuite(
- os.path.join(os.path.pardir, 'doc', test_file),
- setUp=setup_func, tearDown=tearDown,
- layer=DatabaseFunctionalLayer)
+ test_path,
+ id_extensions=[id_ext],
+ setUp=setup_func, tearDown=tearDown,
+ layer=DatabaseFunctionalLayer)
suite.addTest(test)
return suite
=== modified file 'lib/lp/bugs/tests/test_bugcontact.py'
--- lib/lp/bugs/tests/test_bugcontact.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_bugcontact.py 2012-06-06 16:16:31 +0000
@@ -27,8 +27,12 @@
distributionSetUp,
]
+ testname = 'has-bug-supervisor.txt'
for setUpMethod in setUpMethods:
- test = LayeredDocFileSuite('has-bug-supervisor.txt',
+ id_ext = "%s-%s" % (testname, setUpMethod.func_name)
+ test = LayeredDocFileSuite(
+ testname,
+ id_extensions=[id_ext],
setUp=setUpMethod, tearDown=tearDown,
layer=DatabaseFunctionalLayer)
suite.addTest(test)
=== modified file 'lib/lp/bugs/tests/test_buglinktarget.py'
--- lib/lp/bugs/tests/test_buglinktarget.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_buglinktarget.py 2012-06-06 16:16:31 +0000
@@ -51,9 +51,11 @@
]
for name, setUpMethod in targets:
- test = LayeredDocFileSuite('buglinktarget.txt',
- setUp=setUpMethod, tearDown=tearDown,
- layer=LaunchpadFunctionalLayer)
+ test = LayeredDocFileSuite(
+ 'buglinktarget.txt',
+ id_extensions=[name],
+ setUp=setUpMethod, tearDown=tearDown,
+ layer=LaunchpadFunctionalLayer)
suite.addTest(test)
return suite
=== modified file 'lib/lp/bugs/tests/test_bugtarget.py'
--- lib/lp/bugs/tests/test_bugtarget.py 2012-04-17 08:01:35 +0000
+++ lib/lp/bugs/tests/test_bugtarget.py 2012-06-06 16:16:31 +0000
@@ -212,8 +212,12 @@
distributionSeriesSetUp,
]
+ testname = 'bugtarget-questiontarget.txt'
for setUpMethod in setUpMethods:
- test = LayeredDocFileSuite('bugtarget-questiontarget.txt',
+ id_ext = "%s-%s" % (testname, setUpMethod.func_name)
+ test = LayeredDocFileSuite(
+ testname,
+ id_extensions=[id_ext],
setUp=setUpMethod, tearDown=tearDown,
layer=DatabaseFunctionalLayer)
suite.addTest(test)
=== modified file 'lib/lp/bugs/tests/test_doc.py'
--- lib/lp/bugs/tests/test_doc.py 2012-03-27 13:41:38 +0000
+++ lib/lp/bugs/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -141,24 +141,28 @@
),
'bugnotificationrecipients.txt-uploader': LayeredDocFileSuite(
'../doc/bugnotificationrecipients.txt',
+ id_extensions=['bugnotificationrecipients.txt-uploader'],
setUp=uploaderBugsSetUp,
tearDown=uploaderBugsTearDown,
layer=LaunchpadZopelessLayer
),
'bugnotificationrecipients.txt-queued': LayeredDocFileSuite(
'../doc/bugnotificationrecipients.txt',
+ id_extensions=['bugnotificationrecipients.txt-queued'],
setUp=uploadQueueSetUp,
tearDown=uploadQueueTearDown,
layer=LaunchpadZopelessLayer
),
'bugnotificationrecipients.txt-branchscanner': LayeredDocFileSuite(
'../doc/bugnotificationrecipients.txt',
+ id_extensions=['bugnotificationrecipients.txt-branchscanner'],
setUp=branchscannerBugsSetUp,
tearDown=tearDown,
layer=LaunchpadZopelessLayer
),
'bugnotificationrecipients.txt': LayeredDocFileSuite(
'../doc/bugnotificationrecipients.txt',
+ id_extensions=['bugnotificationrecipients.txt'],
setUp=lobotomizeSteveASetUp, tearDown=tearDown,
layer=LaunchpadFunctionalLayer
),
@@ -184,12 +188,14 @@
),
'bug-set-status.txt': LayeredDocFileSuite(
'../doc/bug-set-status.txt',
+ id_extensions=['bug-set-status.txt'],
setUp=uploadQueueSetUp,
tearDown=uploadQueueTearDown,
layer=LaunchpadZopelessLayer
),
'bug-set-status.txt-uploader': LayeredDocFileSuite(
'../doc/bug-set-status.txt',
+ id_extensions=['bug-set-status.txt-uploader'],
setUp=uploaderBugsSetUp,
tearDown=uploaderBugsTearDown,
layer=LaunchpadZopelessLayer
@@ -202,23 +208,27 @@
),
'bugmessage.txt': LayeredDocFileSuite(
'../doc/bugmessage.txt',
+ id_extensions=['bugmessage.txt'],
setUp=noPrivSetUp, tearDown=tearDown,
layer=LaunchpadFunctionalLayer
),
'bugmessage.txt-queued': LayeredDocFileSuite(
'../doc/bugmessage.txt',
+ id_extensions=['bugmessage.txt-queued'],
setUp=uploadQueueSetUp,
tearDown=uploadQueueTearDown,
layer=LaunchpadZopelessLayer
),
'bugmessage.txt-uploader': LayeredDocFileSuite(
'../doc/bugmessage.txt',
+ id_extensions=['bugmessage.txt-uploader'],
setUp=uploaderSetUp,
tearDown=tearDown,
layer=LaunchpadZopelessLayer
),
'bugmessage.txt-checkwatches': LayeredDocFileSuite(
'../doc/bugmessage.txt',
+ id_extensions=['bugmessage.txt-checkwatches'],
setUp=checkwatchesSetUp,
tearDown=tearDown,
layer=LaunchpadZopelessLayer
@@ -429,11 +439,13 @@
),
'bug-set-status.txt-processmail': LayeredDocFileSuite(
'../doc/bug-set-status.txt',
+ id_extensions=['bug-set-status.txt-processmail'],
setUp=bugSetStatusSetUp, tearDown=tearDown,
layer=ProcessMailLayer,
stdout_logging=False),
'bugmessage.txt-processmail': LayeredDocFileSuite(
'../doc/bugmessage.txt',
+ id_extensions=['bugmessage.txt-processmail'],
setUp=bugmessageSetUp, tearDown=tearDown,
layer=ProcessMailLayer,
stdout_logging=False),
@@ -463,8 +475,7 @@
)
# Add special needs tests
- for key in sorted(special):
- special_suite = special[key]
+ for key, special_suite in sorted(special.items()):
suite.addTest(special_suite)
# Add tests using default setup/teardown
=== modified file 'lib/lp/bugs/tests/test_structuralsubscriptiontarget.py'
--- lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2012-06-06 16:16:31 +0000
@@ -557,8 +557,12 @@
distroSeriesSourcePackageSetUp,
]
+ testname = 'structural-subscription-target.txt'
for setUpMethod in setUpMethods:
- test = LayeredDocFileSuite('structural-subscription-target.txt',
+ id_ext = "%s-%s" % (testname, setUpMethod.func_name)
+ test = LayeredDocFileSuite(
+ testname,
+ id_extensions=[id_ext],
setUp=setUpMethod, tearDown=tearDown,
layer=LaunchpadFunctionalLayer)
suite.addTest(test)
=== modified file 'lib/lp/coop/answersbugs/tests/test_doc.py'
--- lib/lp/coop/answersbugs/tests/test_doc.py 2012-01-20 15:42:44 +0000
+++ lib/lp/coop/answersbugs/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -106,20 +106,21 @@
setUp=bugLinkedToQuestionSetUp, tearDown=tearDown,
layer=DatabaseFunctionalLayer),
'notifications-linked-bug.txt': LayeredDocFileSuite(
- 'notifications-linked-bug.txt',
- setUp=bugLinkedToQuestionSetUp, tearDown=tearDown,
- layer=DatabaseFunctionalLayer),
- 'notifications-linked-bug.txt-uploader':
- LayeredDocFileSuite(
- 'notifications-linked-bug.txt',
- setUp=uploaderBugLinkedToQuestionSetUp,
- tearDown=tearDown,
- layer=LaunchpadZopelessLayer),
+ 'notifications-linked-bug.txt',
+ setUp=bugLinkedToQuestionSetUp, tearDown=tearDown,
+ layer=DatabaseFunctionalLayer),
+ 'notifications-linked-bug.txt-uploader': LayeredDocFileSuite(
+ 'notifications-linked-bug.txt',
+ id_extensions=['notifications-linked-bug.txt-uploader'],
+ setUp=uploaderBugLinkedToQuestionSetUp,
+ tearDown=tearDown,
+ layer=LaunchpadZopelessLayer),
'notifications-linked-bug.txt-queued': LayeredDocFileSuite(
- 'notifications-linked-bug.txt',
- setUp=uploadQueueBugLinkedToQuestionSetUp,
- tearDown=tearDown,
- layer=LaunchpadZopelessLayer),
+ 'notifications-linked-bug.txt',
+ id_extensions=['notifications-linked-bug.txt-queued'],
+ setUp=uploadQueueBugLinkedToQuestionSetUp,
+ tearDown=tearDown,
+ layer=LaunchpadZopelessLayer),
}
=== modified file 'lib/lp/registry/tests/test_distribution.py'
--- lib/lp/registry/tests/test_distribution.py 2012-06-04 16:13:51 +0000
+++ lib/lp/registry/tests/test_distribution.py 2012-06-06 16:16:31 +0000
@@ -44,7 +44,7 @@
)
from lp.registry.interfaces.series import SeriesStatus
from lp.registry.tests.test_distroseries import (
- TestDistroSeriesCurrentSourceReleases,
+ CurrentSourceReleasesMixin,
)
from lp.services.database.constants import UTC_NOW
from lp.services.propertycache import get_property_cache
@@ -56,6 +56,7 @@
celebrity_logged_in,
login_person,
person_logged_in,
+ TestCase,
TestCaseWithFactory,
WebServiceTestCase,
)
@@ -278,7 +279,7 @@
class TestDistributionCurrentSourceReleases(
- TestDistroSeriesCurrentSourceReleases):
+ CurrentSourceReleasesMixin, TestCase):
"""Test for Distribution.getCurrentSourceReleases().
This works in the same way as
@@ -290,7 +291,7 @@
release_interface = IDistributionSourcePackageRelease
@property
- def test_target(self):
+ def target(self):
return self.distribution
def test_which_distroseries_does_not_matter(self):
=== modified file 'lib/lp/registry/tests/test_distroseries.py'
--- lib/lp/registry/tests/test_distroseries.py 2012-04-05 15:50:01 +0000
+++ lib/lp/registry/tests/test_distroseries.py 2012-06-06 16:16:31 +0000
@@ -5,6 +5,10 @@
__metaclass__ = type
+__all__ = [
+ 'CurrentSourceReleasesMixin',
+ ]
+
from datetime import timedelta
from logging import getLogger
@@ -48,28 +52,24 @@
)
-class TestDistroSeriesCurrentSourceReleases(TestCase):
- """Test for DistroSeries.getCurrentSourceReleases()."""
-
- layer = LaunchpadFunctionalLayer
- release_interface = IDistroSeriesSourcePackageRelease
-
+class CurrentSourceReleasesMixin:
+ """Mixin class for current source release tests.
+
+ Used by tests of DistroSeries and Distribution. The mixin must not extend
+ TestCase or it will be run by other modules when imported.
+ """
def setUp(self):
# Log in as an admin, so that we can create distributions.
- super(TestDistroSeriesCurrentSourceReleases, self).setUp()
+ super(CurrentSourceReleasesMixin, self).setUp()
login('foo.bar@xxxxxxxxxxxxx')
self.publisher = SoyuzTestPublisher()
self.factory = self.publisher.factory
self.development_series = self.publisher.setUpDefaultDistroSeries()
self.distribution = self.development_series.distribution
- self.published_package = self.test_target.getSourcePackage(
+ self.published_package = self.target.getSourcePackage(
self.publisher.default_package_name)
login(ANONYMOUS)
- @property
- def test_target(self):
- return self.development_series
-
def assertCurrentVersion(self, expected_version, package_name=None):
"""Assert the current version of a package is the expected one.
@@ -80,8 +80,8 @@
"""
if package_name is None:
package_name = self.publisher.default_package_name
- package = self.test_target.getSourcePackage(package_name)
- releases = self.test_target.getCurrentSourceReleases(
+ package = self.target.getSourcePackage(package_name)
+ releases = self.target.getCurrentSourceReleases(
[package.sourcepackagename])
self.assertEqual(releases[package].version, expected_version)
@@ -95,7 +95,7 @@
# source package is used as the key, with
# a DistroSeriesSourcePackageRelease as the values.
self.publisher.getPubSource(version='0.9')
- releases = self.test_target.getCurrentSourceReleases(
+ releases = self.target.getCurrentSourceReleases(
[self.published_package.sourcepackagename])
self.assertTrue(self.published_package in releases)
self.assertTrue(self.release_interface.providedBy(
@@ -170,6 +170,18 @@
self.assertEqual(releases[bar_package].version, '1.0')
+class TestDistroSeriesCurrentSourceReleases(
+ CurrentSourceReleasesMixin, TestCase):
+ """Test for DistroSeries.getCurrentSourceReleases()."""
+
+ layer = LaunchpadFunctionalLayer
+ release_interface = IDistroSeriesSourcePackageRelease
+
+ @property
+ def target(self):
+ return self.development_series
+
+
class TestDistroSeries(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
=== modified file 'lib/lp/registry/tests/test_doc.py'
--- lib/lp/registry/tests/test_doc.py 2012-01-01 02:58:52 +0000
+++ lib/lp/registry/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -85,6 +85,7 @@
),
'mailinglist-xmlrpc.txt-external': LayeredDocFileSuite(
'../doc/mailinglist-xmlrpc.txt',
+ id_extensions=['mailinglist-xmlrpc.txt-external'],
setUp=mailingListXMLRPCExternalSetUp,
tearDown=tearDown,
layer=LaunchpadFunctionalLayer,
@@ -97,6 +98,7 @@
),
'mailinglist-subscriptions-xmlrpc.txt-external': LayeredDocFileSuite(
'../doc/mailinglist-subscriptions-xmlrpc.txt',
+ id_extensions=['mailinglist-subscriptions-xmlrpc.txt-external'],
setUp=mailingListXMLRPCExternalSetUp,
tearDown=tearDown,
layer=LaunchpadFunctionalLayer,
@@ -115,6 +117,7 @@
),
'message-holds-xmlrpc.txt-external': LayeredDocFileSuite(
'../doc/message-holds-xmlrpc.txt',
+ id_extensions=['message-holds-xmlrpc.txt-external'],
setUp=mailingListXMLRPCExternalSetUp,
tearDown=tearDown,
layer=LaunchpadFunctionalLayer,
=== removed file 'lib/lp/services/verification/browser/tests/test_logintoken_corner_cases.py'
--- lib/lp/services/verification/browser/tests/test_logintoken_corner_cases.py 2011-12-28 17:03:06 +0000
+++ lib/lp/services/verification/browser/tests/test_logintoken_corner_cases.py 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Test harness for running the logintoken-corner-cases.txt tests."""
-
-__metaclass__ = type
-
-import unittest
-
-from lp.testing.layers import LaunchpadFunctionalLayer
-from lp.testing.systemdocs import (
- LayeredDocFileSuite,
- setUp,
- tearDown,
- )
-
-
-def test_suite():
- suite = unittest.TestSuite()
-
- test = LayeredDocFileSuite('logintoken-corner-cases.txt',
- setUp=setUp, tearDown=tearDown,
- layer=LaunchpadFunctionalLayer)
- suite.addTest(test)
- return suite
=== modified file 'lib/lp/services/webservice/tests/test_doc.py'
--- lib/lp/services/webservice/tests/test_doc.py 2012-01-01 02:58:52 +0000
+++ lib/lp/services/webservice/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -39,8 +39,9 @@
'../doc/launchpadlib.txt',
layer=AppServerLayer,
setUp=browser.setUp, tearDown=browser.tearDown,),
- 'launchpadlib2.txt': LayeredDocFileSuite(
+ 'launchpadlib.txt-2': LayeredDocFileSuite(
'../doc/launchpadlib.txt',
+ id_extensions=['launchpadlib.txt-2'],
layer=AppServerLayer,
setUp=browser.setUp, tearDown=browser.tearDown,),
}
=== modified file 'lib/lp/soyuz/tests/test_doc.py'
--- lib/lp/soyuz/tests/test_doc.py 2012-05-30 12:34:41 +0000
+++ lib/lp/soyuz/tests/test_doc.py 2012-06-06 16:16:31 +0000
@@ -132,6 +132,7 @@
),
'closing-bugs-from-changelogs.txt-uploader': LayeredDocFileSuite(
'../doc/closing-bugs-from-changelogs.txt',
+ id_extensions=['closing-bugs-from-changelogs.txt-uploader'],
setUp=uploaderBugsSetUp,
tearDown=uploaderBugsTearDown,
layer=LaunchpadZopelessLayer
=== modified file 'lib/lp/testing/pages.py'
--- lib/lp/testing/pages.py 2012-01-31 01:19:45 +0000
+++ lib/lp/testing/pages.py 2012-06-06 16:16:31 +0000
@@ -843,9 +843,10 @@
# Add tests to the suite individually.
if filenames:
checker = doctest.OutputChecker()
+ paths=[os.path.join(storydir, filename)
+ for filename in filenames]
suite.addTest(LayeredDocFileSuite(
+ paths=paths,
package=package, checker=checker, stdout_logging=False,
- layer=PageTestLayer, setUp=setUp,
- *[os.path.join(storydir, filename)
- for filename in filenames]))
+ layer=PageTestLayer, setUp=setUp))
return suite
=== modified file 'lib/lp/testing/systemdocs.py'
--- lib/lp/testing/systemdocs.py 2011-12-30 06:14:56 +0000
+++ lib/lp/testing/systemdocs.py 2012-06-06 16:16:31 +0000
@@ -89,7 +89,7 @@
record.levelname, record.name, self.format(record))
-def LayeredDocFileSuite(*paths, **kw):
+def LayeredDocFileSuite(paths, id_extensions=None, **kw):
"""Create a DocFileSuite, optionally applying a layer to it.
In addition to the standard DocFileSuite arguments, the following
@@ -101,6 +101,10 @@
:param layer: A Zope test runner layer to apply to the tests (by
default no layer is applied).
"""
+ if not isinstance(paths, (tuple, list)):
+ paths = [paths]
+ if id_extensions is None:
+ id_extensions = []
kw.setdefault('optionflags', default_optionflags)
kw.setdefault('parser', default_parser)
@@ -142,14 +146,21 @@
if layer is not None:
suite.layer = layer
- for test in suite:
+ for i, test in enumerate(suite):
# doctest._module_relative_path() does not normalize paths. To make
# test selection simpler and reporting easier to read, normalize here.
test._dt_test.filename = os.path.normpath(test._dt_test.filename)
# doctest.DocFileTest insists on using the basename of the file as the
# test ID. This causes conflicts when two doctests have the same
# filename, so we patch the id() method on the test cases.
- test.id = partial(lambda test: test._dt_test.filename, test)
+ try:
+ ext = id_extensions[i]
+ newid = os.path.join(
+ os.path.dirname(test._dt_test.filename),
+ ext)
+ test.id = partial(lambda x: x, newid)
+ except IndexError:
+ test.id = partial(lambda test: test._dt_test.filename, test)
return suite
@@ -162,14 +173,6 @@
We do this because dict ordering is not guaranteed.
"""
- # XXX 2008-06-25 gmb:
- # Once we move to Python 2.5 we won't need this, since dict
- # ordering is guaranteed when __str__() is called.
- item_string = '%r: %r'
- item_strings = []
- for key, value in sorted(dict.items()):
- item_strings.append(item_string % (key, value))
-
return '{%s}' % ', '.join(
"%r: %r" % (key, value) for key, value in sorted(dict.items()))
=== modified file 'lib/lp/testing/tests/test_inlinetests.py'
--- lib/lp/testing/tests/test_inlinetests.py 2012-01-01 02:58:52 +0000
+++ lib/lp/testing/tests/test_inlinetests.py 2012-06-06 16:16:31 +0000
@@ -16,8 +16,8 @@
def test_suite():
suite = LayeredDocFileSuite(
+ [],
layer=BaseLayer)
suite.addTest(doctest.DocTestSuite(
testing, optionflags=NORMALIZE_WHITESPACE|ELLIPSIS))
return suite
-
=== modified file 'versions.cfg'
--- versions.cfg 2012-05-23 22:40:28 +0000
+++ versions.cfg 2012-06-06 16:16:31 +0000
@@ -299,7 +299,7 @@
# Run "python bootstrap.py; ./bin/buildout".
# Make sure you have subunit installed. When running tests, be aware that
# three will fail initially, per http://pastebin.ubuntu.com/913757/ .
-zope.testing = 3.9.4-p6
+zope.testing = 3.9.4-p7
zope.thread = 3.4
zope.traversing = 3.8.0
zope.viewlet = 3.6.1
Follow ups