← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/remove-bzrlib-multiply-tests into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-bzrlib-multiply-tests into lp:launchpad.

Commit message:
Convert all users of bzrlib.tests.multiply_tests to testscenarios.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-bzrlib-multiply-tests/+merge/314002

testscenarios seems to be working well, so let's only have one implementation of test multiplication in use.

I also removed a few unnecessary test_suite functions (confirmed by comparing test output before and after).
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-bzrlib-multiply-tests into lp:launchpad.
=== modified file 'lib/lp/code/model/tests/test_codeimportjob.py'
--- lib/lp/code/model/tests/test_codeimportjob.py	2016-10-20 09:34:02 +0000
+++ lib/lp/code/model/tests/test_codeimportjob.py	2017-01-03 11:44:53 +0000
@@ -11,7 +11,6 @@
 
 from datetime import datetime
 import StringIO
-import unittest
 
 from pymacaroons import Macaroon
 from pytz import UTC
@@ -1243,7 +1242,3 @@
         issuer = getUtility(IMacaroonIssuer, "code-import-job")
         macaroon = removeSecurityProxy(issuer).issueMacaroon(other_job)
         self.assertFalse(issuer.verifyMacaroon(macaroon, job))
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/model/tests/test_linkedbranch.py'
--- lib/lp/code/model/tests/test_linkedbranch.py	2012-01-01 02:58:52 +0000
+++ lib/lp/code/model/tests/test_linkedbranch.py	2017-01-03 11:44:53 +0000
@@ -5,9 +5,6 @@
 
 __metaclass__ = type
 
-
-import unittest
-
 from zope.security.proxy import removeSecurityProxy
 
 from lp.code.interfaces.linkedbranch import (
@@ -353,7 +350,3 @@
         self.assertIs(meerkat_2_devel_backports, links[5])
         self.assertIs(meerkat_1, links[6])
         self.assertIs(zebra, links[7])
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/code/xmlrpc/tests/test_codehosting.py'
--- lib/lp/code/xmlrpc/tests/test_codehosting.py	2016-02-05 16:51:12 +0000
+++ lib/lp/code/xmlrpc/tests/test_codehosting.py	2017-01-03 11:44:53 +0000
@@ -7,12 +7,14 @@
 
 import datetime
 import os
-import unittest
 
 from bzrlib import bzrdir
-from bzrlib.tests import multiply_tests
 from bzrlib.urlutils import escape
 import pytz
+from testscenarios import (
+    load_tests_apply_scenarios,
+    WithScenarios,
+    )
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
@@ -161,13 +163,56 @@
         self.assertEqual(None, login_id)
 
 
-class CodehostingTest(TestCaseWithFactory):
+class LaunchpadDatabaseFrontend:
+    """A 'frontend' to Launchpad's branch services.
+
+    A 'frontend' here means something that provides access to the various
+    XML-RPC endpoints, object factories and 'database' methods needed to write
+    unit tests for XML-RPC endpoints.
+
+    All of these methods are gathered together in this class so that
+    alternative implementations can be provided, see `InMemoryFrontend`.
+    """
+
+    def getCodehostingEndpoint(self):
+        """Return the branch filesystem endpoint for testing."""
+        return CodehostingAPI(None, None)
+
+    def getLaunchpadObjectFactory(self):
+        """Return the Launchpad object factory for testing.
+
+        See `LaunchpadObjectFactory`.
+        """
+        return LaunchpadObjectFactory()
+
+    def getBranchLookup(self):
+        """Return an implementation of `IBranchLookup`.
+
+        Tests should use this to get the branch set they need, rather than
+        using 'getUtility(IBranchSet)'. This allows in-memory implementations
+        to work correctly.
+        """
+        return getUtility(IBranchLookup)
+
+    def getLastActivity(self, activity_name):
+        """Get the last script activity with 'activity_name'."""
+        return getUtility(IScriptActivitySet).getLastActivity(activity_name)
+
+
+class CodehostingTest(WithScenarios, TestCaseWithFactory):
     """Tests for the implementation of `ICodehostingAPI`.
 
     :ivar frontend: A nullary callable that returns an object that implements
         getCodehostingEndpoint, getLaunchpadObjectFactory and getBranchLookup.
     """
 
+    scenarios = [
+        ('db', {'frontend': LaunchpadDatabaseFrontend,
+                'layer': LaunchpadFunctionalLayer}),
+        ('inmemory', {'frontend': InMemoryFrontend,
+                      'layer': FunctionalLayer}),
+        ]
+
     def setUp(self):
         TestCaseWithFactory.setUp(self)
         frontend = self.frontend()
@@ -1235,10 +1280,17 @@
             trailing_path='.bzr')
 
 
-class AcquireBranchToPullTestsViaEndpoint(TestCaseWithFactory,
+class AcquireBranchToPullTestsViaEndpoint(WithScenarios, TestCaseWithFactory,
                                           AcquireBranchToPullTests):
     """Tests for `acquireBranchToPull` method of `ICodehostingAPI`."""
 
+    scenarios = [
+        ('db', {'frontend': LaunchpadDatabaseFrontend,
+                'layer': LaunchpadFunctionalLayer}),
+        ('inmemory', {'frontend': InMemoryFrontend,
+                      'layer': FunctionalLayer}),
+        ]
+
     def setUp(self):
         super(AcquireBranchToPullTestsViaEndpoint, self).setUp()
         frontend = self.frontend()
@@ -1321,55 +1373,4 @@
             ('NO_SUCH_TYPE',))
 
 
-class LaunchpadDatabaseFrontend:
-    """A 'frontend' to Launchpad's branch services.
-
-    A 'frontend' here means something that provides access to the various
-    XML-RPC endpoints, object factories and 'database' methods needed to write
-    unit tests for XML-RPC endpoints.
-
-    All of these methods are gathered together in this class so that
-    alternative implementations can be provided, see `InMemoryFrontend`.
-    """
-
-    def getCodehostingEndpoint(self):
-        """Return the branch filesystem endpoint for testing."""
-        return CodehostingAPI(None, None)
-
-    def getLaunchpadObjectFactory(self):
-        """Return the Launchpad object factory for testing.
-
-        See `LaunchpadObjectFactory`.
-        """
-        return LaunchpadObjectFactory()
-
-    def getBranchLookup(self):
-        """Return an implementation of `IBranchLookup`.
-
-        Tests should use this to get the branch set they need, rather than
-        using 'getUtility(IBranchSet)'. This allows in-memory implementations
-        to work correctly.
-        """
-        return getUtility(IBranchLookup)
-
-    def getLastActivity(self, activity_name):
-        """Get the last script activity with 'activity_name'."""
-        return getUtility(IScriptActivitySet).getLastActivity(activity_name)
-
-
-def test_suite():
-    loader = unittest.TestLoader()
-    suite = unittest.TestSuite()
-    endpoint_tests = unittest.TestSuite(
-        [loader.loadTestsFromTestCase(AcquireBranchToPullTestsViaEndpoint),
-         loader.loadTestsFromTestCase(CodehostingTest),
-         ])
-    scenarios = [
-        ('db', {'frontend': LaunchpadDatabaseFrontend,
-                'layer': LaunchpadFunctionalLayer}),
-        ('inmemory', {'frontend': InMemoryFrontend,
-                      'layer': FunctionalLayer}),
-        ]
-    multiply_tests(endpoint_tests, scenarios, suite)
-    suite.addTests(loader.loadTestsFromTestCase(TestRunWithLogin))
-    return suite
+load_tests = load_tests_apply_scenarios

=== modified file 'lib/lp/codehosting/tests/helpers.py'
--- lib/lp/codehosting/tests/helpers.py	2015-09-28 17:38:45 +0000
+++ lib/lp/codehosting/tests/helpers.py	2017-01-03 11:44:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Common helpers for codehosting tests."""
@@ -6,8 +6,6 @@
 __metaclass__ = type
 __all__ = [
     'AvatarTestCase',
-    'adapt_suite',
-    'CodeHostingTestProviderAdapter',
     'create_branch_with_one_revision',
     'deferToThread',
     'force_stacked_on_url',
@@ -18,7 +16,6 @@
 
 import os
 import threading
-import unittest
 
 from bzrlib.bzrdir import BzrDir
 from bzrlib.errors import FileExists
@@ -113,37 +110,6 @@
     return mergeFunctionMetadata(f, decorated)
 
 
-def clone_test(test, new_id):
-    """Return a clone of the given test."""
-    from copy import deepcopy
-    new_test = deepcopy(test)
-
-    def make_new_test_id():
-        return lambda: new_id
-
-    new_test.id = make_new_test_id()
-    return new_test
-
-
-class CodeHostingTestProviderAdapter:
-    """Test adapter to run a single test against many codehosting servers."""
-
-    def __init__(self, schemes):
-        self._schemes = schemes
-
-    def adaptForServer(self, test, scheme):
-        new_test = clone_test(test, '%s(%s)' % (test.id(), scheme))
-        new_test.scheme = scheme
-        return new_test
-
-    def adapt(self, test):
-        result = unittest.TestSuite()
-        for scheme in self._schemes:
-            new_test = self.adaptForServer(test, scheme)
-            result.addTest(new_test)
-        return result
-
-
 def make_bazaar_branch_and_tree(db_branch):
     """Make a dummy Bazaar branch and working tree from a database Branch."""
     assert db_branch.branch_type == BranchType.HOSTED, (
@@ -155,14 +121,6 @@
     return create_branch_with_one_revision(branch_dir)
 
 
-def adapt_suite(adapter, base_suite):
-    from bzrlib.tests import iter_suite_tests
-    suite = unittest.TestSuite()
-    for test in iter_suite_tests(base_suite):
-        suite.addTests(adapter.adapt(test))
-    return suite
-
-
 def create_branch_with_one_revision(branch_dir, format=None):
     """Create a dummy Bazaar branch at the given directory."""
     if not os.path.exists(branch_dir):

=== modified file 'lib/lp/codehosting/tests/test_acceptance.py'
--- lib/lp/codehosting/tests/test_acceptance.py	2015-09-28 17:38:45 +0000
+++ lib/lp/codehosting/tests/test_acceptance.py	2017-01-03 11:44:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Acceptance tests for the codehosting server."""
@@ -12,17 +12,18 @@
 import subprocess
 import sys
 import time
-import unittest
 import urllib2
 import xmlrpclib
 
 import bzrlib.branch
-from bzrlib.tests import (
-    multiply_tests,
-    TestCaseWithTransport,
-    )
+from bzrlib.tests import TestCaseWithTransport
+from bzrlib.tests.per_repository import all_repository_format_scenarios
 from bzrlib.urlutils import local_path_from_url
 from bzrlib.workingtree import WorkingTree
+from testscenarios import (
+    load_tests_apply_scenarios,
+    WithScenarios,
+    )
 from zope.component import getUtility
 
 from lp.code.bzr import (
@@ -41,10 +42,7 @@
     get_BZR_PLUGIN_PATH_for_subprocess,
     )
 from lp.codehosting.bzrutils import DenyingServer
-from lp.codehosting.tests.helpers import (
-    adapt_suite,
-    LoomTestMixin,
-    )
+from lp.codehosting.tests.helpers import LoomTestMixin
 from lp.codehosting.tests.servers import (
     CodeHostingTac,
     set_up_test_user,
@@ -340,9 +338,27 @@
         return branch_url
 
 
-class SmokeTest(SSHTestCase):
+class SmokeTest(WithScenarios, SSHTestCase):
     """Smoke test for repository support."""
 
+    excluded_scenarios = [
+        # RepositoryFormat4 is not initializable (bzrlib raises TestSkipped
+        # when you try).
+        'RepositoryFormat4',
+        # Fetching weave formats from the smart server is known to be broken.
+        # See bug 173807 and bzrlib.tests.test_repository.
+        'RepositoryFormat5',
+        'RepositoryFormat6',
+        'RepositoryFormat7',
+        'GitRepositoryFormat',
+        'SvnRepositoryFormat',
+        ]
+
+    scenarios = [
+        scenario for scenario in all_repository_format_scenarios()
+        if scenario[0] not in excluded_scenarios
+        and not scenario[0].startswith('RemoteRepositoryFormat')]
+
     def setUp(self):
         self.scheme = 'bzr+ssh'
         super(SmokeTest, self).setUp()
@@ -380,13 +396,18 @@
         self.assertBranchesMatch(self.first_tree, self.second_tree)
 
 
-class AcceptanceTests(SSHTestCase):
+class AcceptanceTests(WithScenarios, SSHTestCase):
     """Acceptance tests for the Launchpad codehosting service.
 
     Originally converted from the English at
     https://launchpad.canonical.com/SupermirrorTaskList
     """
 
+    scenarios = [
+        ('sftp', {'scheme': 'sftp'}),
+        ('bzr+ssh', {'scheme': 'bzr+ssh'}),
+        ]
+
     def assertNotBranch(self, url):
         """Assert that there's no branch at 'url'."""
         error_line = self._run_bzr_error(
@@ -650,9 +671,13 @@
         self.assertBranchesMatch('loom', remote_url)
 
 
-class SmartserverTests(SSHTestCase):
+class SmartserverTests(WithScenarios, SSHTestCase):
     """Acceptance tests for the codehosting smartserver."""
 
+    scenarios = [
+        ('bzr+ssh', {'scheme': 'bzr+ssh'}),
+        ]
+
     def makeMirroredBranch(self, person_name, product_name, branch_name):
         ro_branch_url = self.createBazaarBranch(
             person_name, product_name, branch_name)
@@ -727,45 +752,4 @@
         urllib2.urlopen(web_status_url)
 
 
-def make_server_tests(base_suite, servers):
-    from lp.codehosting.tests.helpers import (
-        CodeHostingTestProviderAdapter)
-    adapter = CodeHostingTestProviderAdapter(servers)
-    return adapt_suite(adapter, base_suite)
-
-
-def make_smoke_tests(base_suite):
-    from bzrlib.tests.per_repository import (
-        all_repository_format_scenarios,
-        )
-    excluded_scenarios = [
-        # RepositoryFormat4 is not initializable (bzrlib raises TestSkipped
-        # when you try).
-        'RepositoryFormat4',
-        # Fetching weave formats from the smart server is known to be broken.
-        # See bug 173807 and bzrlib.tests.test_repository.
-        'RepositoryFormat5',
-        'RepositoryFormat6',
-        'RepositoryFormat7',
-        'GitRepositoryFormat',
-        'SvnRepositoryFormat',
-        ]
-    scenarios = all_repository_format_scenarios()
-    scenarios = [
-        scenario for scenario in scenarios
-        if scenario[0] not in excluded_scenarios
-        and not scenario[0].startswith('RemoteRepositoryFormat')]
-    new_suite = unittest.TestSuite()
-    multiply_tests(base_suite, scenarios, new_suite)
-    return new_suite
-
-
-def test_suite():
-    base_suite = unittest.makeSuite(AcceptanceTests)
-    suite = unittest.TestSuite()
-
-    suite.addTest(make_server_tests(base_suite, ['sftp', 'bzr+ssh']))
-    suite.addTest(make_server_tests(
-            unittest.makeSuite(SmartserverTests), ['bzr+ssh']))
-    suite.addTest(make_smoke_tests(unittest.makeSuite(SmokeTest)))
-    return suite
+load_tests = load_tests_apply_scenarios

=== modified file 'lib/lp/codehosting/tests/test_bzrutils.py'
--- lib/lp/codehosting/tests/test_bzrutils.py	2015-07-06 14:12:12 +0000
+++ lib/lp/codehosting/tests/test_bzrutils.py	2017-01-03 11:44:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for bzrutils."""
@@ -17,16 +17,18 @@
 from bzrlib.errors import AppendRevisionsOnlyViolation
 from bzrlib.remote import RemoteBranch
 from bzrlib.tests import (
-    multiply_tests,
     test_server,
     TestCaseWithTransport,
-    TestLoader,
     TestNotApplicable,
     )
 from bzrlib.tests.per_branch import (
     branch_scenarios,
     TestCaseWithControlDir,
     )
+from testscenarios import (
+    load_tests_apply_scenarios,
+    WithScenarios,
+    )
 
 from lp.codehosting.bzrutils import (
     add_exception_logging_hook,
@@ -41,9 +43,19 @@
 from lp.testing import TestCase
 
 
-class TestGetBranchStackedOnURL(TestCaseWithControlDir):
+class TestGetBranchStackedOnURL(WithScenarios, TestCaseWithControlDir):
     """Tests for get_branch_stacked_on_url()."""
 
+    excluded_scenarios = [
+        'BranchReferenceFormat',
+        'GitBranchFormat',
+        'SvnBranchFormat',
+        ]
+
+    scenarios = [
+        scenario for scenario in branch_scenarios()
+        if scenario[0] not in excluded_scenarios]
+
     def __str__(self):
         """Return the test id so that Zope test output shows the format."""
         return self.id()
@@ -228,25 +240,4 @@
             get_vfs_format_classes(remote_branch))
 
 
-def load_tests(basic_tests, module, loader):
-    """Parametrize the tests of get_branch_stacked_on_url by branch format."""
-    result = loader.suiteClass()
-
-    get_branch_stacked_on_url_tests = loader.loadTestsFromTestCase(
-        TestGetBranchStackedOnURL)
-    scenarios = [scenario for scenario in branch_scenarios()
-                 if scenario[0] not in (
-                     'BranchReferenceFormat', 'GitBranchFormat',
-                     'SvnBranchFormat')]
-    multiply_tests(get_branch_stacked_on_url_tests, scenarios, result)
-
-    result.addTests(loader.loadTestsFromTestCase(TestIsBranchStackable))
-    result.addTests(loader.loadTestsFromTestCase(TestDenyingServer))
-    result.addTests(loader.loadTestsFromTestCase(TestExceptionLoggingHooks))
-    result.addTests(loader.loadTestsFromTestCase(TestGetVfsFormatClasses))
-    return result
-
-
-def test_suite():
-    loader = TestLoader()
-    return loader.loadTestsFromName(__name__)
+load_tests = load_tests_apply_scenarios

=== modified file 'lib/lp/registry/tests/test_packaging.py'
--- lib/lp/registry/tests/test_packaging.py	2015-06-26 09:59:30 +0000
+++ lib/lp/registry/tests/test_packaging.py	2017-01-03 11:44:53 +0000
@@ -5,8 +5,6 @@
 
 __metaclass__ = type
 
-from unittest import TestLoader
-
 from lazr.lifecycle.event import (
     ObjectCreatedEvent,
     ObjectDeletedEvent,
@@ -303,7 +301,3 @@
         (event,) = recorder.events
         self.assertIsInstance(event, ObjectDeletedEvent)
         self.assertIs(removeSecurityProxy(packaging), event.object)
-
-
-def test_suite():
-    return TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/services/scripts/tests/test_all_scripts.py'
--- lib/lp/services/scripts/tests/test_all_scripts.py	2013-03-20 03:41:40 +0000
+++ lib/lp/services/scripts/tests/test_all_scripts.py	2017-01-03 11:44:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Check the integrity of the /scripts and /cronscripts."""
@@ -7,9 +7,11 @@
 
 import doctest
 import os
-import unittest
 
-from testtools import clone_test_with_new_id
+from testscenarios import (
+    load_tests_apply_scenarios,
+    WithScenarios,
+    )
 from testtools.matchers import DocTestMatches
 
 from lp.services.scripts.tests import find_lp_scripts
@@ -19,9 +21,17 @@
     )
 
 
-class ScriptsTestCase(TestCase):
+def make_id(script_path):
+    return 'script_' + os.path.splitext(os.path.basename(script_path))[0]
+
+
+class ScriptsTestCase(WithScenarios, TestCase):
     """Check the integrity of all scripts shipped in the tree."""
 
+    scenarios = [
+        (make_id(script_path), {'script_path': script_path})
+        for script_path in find_lp_scripts()]
+
     def test_script(self):
         # Run self.script_path with '-h' to make sure it runs cleanly.
         cmd_line = self.script_path + " -h"
@@ -31,19 +41,4 @@
         self.assertEqual(os.EX_OK, returncode)
 
 
-def make_new_id(old_id, script_path):
-    base, name = old_id.rsplit('.', 1)
-    script_name = os.path.splitext(os.path.basename(script_path))[0]
-    return '.'.join([base, 'script_' + script_name])
-
-
-def test_suite():
-    test = ScriptsTestCase('test_script')
-    test_id = test.id()
-    suite = unittest.TestSuite()
-    for script_path in find_lp_scripts():
-        new_test = clone_test_with_new_id(
-            test, make_new_id(test_id, script_path))
-        new_test.script_path = script_path
-        suite.addTest(new_test)
-    return suite
+load_tests = load_tests_apply_scenarios

=== modified file 'lib/lp/services/tests/test_browser_helpers.py'
--- lib/lp/services/tests/test_browser_helpers.py	2015-10-14 15:22:01 +0000
+++ lib/lp/services/tests/test_browser_helpers.py	2017-01-03 11:44:53 +0000
@@ -4,7 +4,7 @@
 """Unit tests for browser helper functions."""
 
 __metaclass__ = type
-__all__ = ['TestGetUserAgentDistroSeries', 'test_suite']
+__all__ = ['TestGetUserAgentDistroSeries']
 
 import unittest
 
@@ -35,7 +35,3 @@
         version = get_user_agent_distroseries(user_agent)
         self.failUnless(version is None,
                         "None should be returned when the match fails.")
-
-
-def test_suite():
-    return unittest.TestLoader().loadTestsFromName(__name__)


Follow ups