← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/private-bug-1 into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/private-bug-1 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/private-bug-1/+merge/71767

Replace doctests with unittests before working on bug 797697.

This branch removes inline and file doctests of classes I am changing in my next branch. These was one minor change test__normalizePath_distros was duplicated in the doctest. I think this was a typo because there was no test__normalizePath_products which I added.

LINT

    lib/lp/bugs/mail/commands.py
    lib/lp/bugs/mail/tests/test_commands.py


TEST

    ./bin/test -vv lp.bugs.mail.tests.test_commands


IMPLEMENTATION

Extracted doctests from classmethods.
    lib/lp/bugs/mail/commands.py
    lib/lp/bugs/mail/tests/test_commands.py

Replaces doctest for getBugTarget with unittest.
    lib/lp/bugs/doc/bugs-email-affects-path.txt
    lib/lp/bugs/mail/tests/test_commands.py
-- 
https://code.launchpad.net/~sinzui/launchpad/private-bug-1/+merge/71767
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/private-bug-1 into lp:launchpad.
=== removed file 'lib/lp/bugs/doc/bugs-email-affects-path.txt'
--- lib/lp/bugs/doc/bugs-email-affects-path.txt	2011-08-11 21:17:02 +0000
+++ lib/lp/bugs/doc/bugs-email-affects-path.txt	1970-01-01 00:00:00 +0000
@@ -1,221 +0,0 @@
-The 'affects' path in the Bugs e-mail interface
-===============================================
-
-When choosing which bugtask certain e-mail commands should modify, the
-'affects' command is used. It accepts a single argument, the name of the
-bug target the bugtask should target. The conversion of a name to an
-IBugTarget is done by the AffectsEmailCommand.getBugTarget method.
-
-    >>> from lp.bugs.mail.commands import AffectsEmailCommand
-
-It accepts a single parameter, the name/path of the bugtarget. If a
-non-existant name/path is given an exception is raised with an
-appropriate error message
-
-    >>> AffectsEmailCommand.getBugTarget('non-existant')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: There is no project named 'non-existant'
-                       registered in Launchpad.
-
-The same exception is raised also when the name contains slashes:
-
-    >>> AffectsEmailCommand.getBugTarget('non-existant/dapper/evolution')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: There is no project named 'non-existant'
-                       registered in Launchpad.
-
-Even though a ProjectGroup is an IBugTarget, it's not possible to file bugs
-on it, so an exception with an appropriate error message is raised.
-
-    >>> AffectsEmailCommand.getBugTarget('gnome')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: gnome is a group of projects. To report a bug,
-                       you need to specify which of these projects the
-                       bug applies to: evolution, gnome-terminal, applets,
-                       netapplet, gnomebaker
-
-
-Getting a product
------------------
-
-Getting a product is done by specifying the name of the product.
-
-    >>> from lp.registry.interfaces.product import IProduct
-    >>> evolution = AffectsEmailCommand.getBugTarget('evolution')
-    >>> IProduct.providedBy(evolution)
-    True
-    >>> evolution.name
-    u'evolution'
-
-Inactive products are treated like non-existant ones.
-
-    >>> from lp.registry.interfaces.product import IProductSet
-    >>> unassigned = getUtility(IProductSet).getByName('unassigned')
-    >>> unassigned.active
-    False
-    >>> AffectsEmailCommand.getBugTarget(unassigned.name)
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: There is no project named 'unassigned'
-                       registered in Launchpad.
-
-
-Getting a product series
-------------------------
-
-A product series is a part of a product, so both the product and series
-name have to be given, separated with a slash.
-
-    >>> from lp.registry.interfaces.productseries import IProductSeries
-    >>> evolution_trunk = AffectsEmailCommand.getBugTarget('evolution/trunk')
-    >>> IProductSeries.providedBy(evolution_trunk)
-    True
-    >>> evolution_trunk.product.name
-    u'evolution'
-    >>> evolution_trunk.name
-    u'trunk'
-
-If a non-existant product series is given, an exception is raised with
-an appropriate error message.
-
-    >>> AffectsEmailCommand.getBugTarget('evolution/non-existant')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Evolution doesn't have a series named 'non-existant'.
-
-If some additional path component is included after the series, an
-exception with an appropriate error is raised.
-
-    >>> AffectsEmailCommand.getBugTarget('evolution/trunk/foo')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Unexpected path components: foo
-
-
-Getting a distribution
-----------------------
-
-Getting a distribution is done by specifying the name of the
-distribution.
-
-    >>> from lp.registry.interfaces.distribution import IDistribution
-    >>> ubuntu = AffectsEmailCommand.getBugTarget('ubuntu')
-    >>> IDistribution.providedBy(ubuntu)
-    True
-    >>> ubuntu.name
-    u'ubuntu'
-
-
-Getting a source package in a distribution
-..........................................
-
-A distribution source package is a part of a distribution, so both the
-distribution and package name has to be specified when getting such a
-package.
-
-    >>> from lp.registry.interfaces.distributionsourcepackage import (
-    ...     IDistributionSourcePackage)
-    >>> ubuntu_evolution = AffectsEmailCommand.getBugTarget(
-    ...     'ubuntu/evolution')
-    >>> IDistributionSourcePackage.providedBy(ubuntu_evolution)
-    True
-    >>> ubuntu_evolution.name
-    u'evolution'
-    >>> ubuntu_evolution.distribution.name
-    u'ubuntu'
-
-If a non-existant source package is given, an exception is raised with
-an appropriate error message.
-
-    >>> AffectsEmailCommand.getBugTarget('ubuntu/non-existant')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Ubuntu doesn't have a series or source package
-                       named 'non-existant'.
-
-If some additional path component is included after the package, an
-exception with an appropriate error is raised.
-
-    >>> AffectsEmailCommand.getBugTarget('ubuntu/evolution/foo')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Unexpected path components: foo
-
-
-Getting a distribution series
------------------------------
-
-A distribution series is a part of a distribution, so both the
-distribution and series has to be specified.
-
-    >>> from lp.registry.interfaces.distroseries import IDistroSeries
-    >>> ubuntu_warty = AffectsEmailCommand.getBugTarget('ubuntu/warty')
-    >>> IDistroSeries.providedBy(ubuntu_warty)
-    True
-    >>> ubuntu_warty.name
-    u'warty'
-    >>> ubuntu_warty.distribution.name
-    u'ubuntu'
-
-The path structure for a distribution series is the same as for a
-distribution source package, so the same error handling is used for
-both.
-
-
-Getting a source package in a distribution series
--------------------------------------------------
-
-When getting a source package within a distribution series, the source
-package is given after the distribution series.
-
-    >>> from lp.registry.interfaces.sourcepackage import ISourcePackage
-    >>> warty_evolution = AffectsEmailCommand.getBugTarget(
-    ...     'ubuntu/warty/evolution')
-    >>> ISourcePackage.providedBy(warty_evolution)
-    True
-    >>> warty_evolution.name
-    u'evolution'
-    >>> warty_evolution.distroseries.name
-    u'warty'
-    >>> warty_evolution.distroseries.distribution.name
-    u'ubuntu'
-
-If a non-existant source package is given, an exception is raised with
-an appropriate error message.
-
-    >>> AffectsEmailCommand.getBugTarget('ubuntu/warty/non-existant')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Warty doesn't have a series or source package
-                       named 'non-existant'.
-
-If some additional path component is included after the package, an
-exception with an appropriate error is raised.
-
-    >>> AffectsEmailCommand.getBugTarget('ubuntu/warty/evolution/foo')
-    Traceback (most recent call last):
-    ...
-    BugTargetNotFound: Unexpected path components: foo
-
-
-Error correction
-----------------
-
-Previously the affects path was resolved in the same way, except that
-either /distros/ or /products/ was needed in the front. Since people are
-used to this syntax, we accept it as well.
-
-    >>> ubuntu = AffectsEmailCommand.getBugTarget('/distros/ubuntu')
-    >>> IDistribution.providedBy(ubuntu)
-    True
-    >>> ubuntu.name
-    u'ubuntu'
-
-    >>> evolution = AffectsEmailCommand.getBugTarget('/products/evolution')
-    >>> IProduct.providedBy(evolution)
-    True
-    >>> evolution.name
-    u'evolution'

=== modified file 'lib/lp/bugs/mail/commands.py'
--- lib/lp/bugs/mail/commands.py	2011-08-12 14:39:51 +0000
+++ lib/lp/bugs/mail/commands.py	2011-08-16 19:26:24 +0000
@@ -428,15 +428,7 @@
         """Split the path part into two.
 
         The first part is the part before any slash, and the other is
-        the part behind the slash:
-
-            >>> AffectsEmailCommand._splitPath('foo/bar/baz')
-            ('foo', 'bar/baz')
-
-        If No slash is in the path, the other part will be empty.
-
-            >>> AffectsEmailCommand._splitPath('foo')
-            ('foo', '')
+        the part behind the slash.
         """
         if '/' not in path:
             return path, ''
@@ -450,16 +442,6 @@
         Previously the path had to start with either /distros/ or
         /products/. Simply remove any such prefixes to stay backward
         compatible.
-
-            >>> AffectsEmailCommand._normalizePath('/distros/foo/bar')
-            'foo/bar'
-            >>> AffectsEmailCommand._normalizePath('/distros/foo/bar')
-            'foo/bar'
-
-        Also remove a starting slash, since that's a common mistake.
-
-            >>> AffectsEmailCommand._normalizePath('/foo/bar')
-            'foo/bar'
         """
         for prefix in ['/distros/', '/products/', '/']:
             if path.startswith(prefix):

=== modified file 'lib/lp/bugs/mail/tests/test_commands.py'
--- lib/lp/bugs/mail/tests/test_commands.py	2011-08-12 14:36:25 +0000
+++ lib/lp/bugs/mail/tests/test_commands.py	2011-08-16 19:26:24 +0000
@@ -1,8 +1,145 @@
 # Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from doctest import DocTestSuite
-
-
-def test_suite():
-    return DocTestSuite('lp.bugs.mail.commands')
+from canonical.testing.layers import DatabaseFunctionalLayer
+from lp.bugs.mail.commands import (
+    AffectsEmailCommand,
+    )
+from lp.services.mail.interfaces import BugTargetNotFound
+from lp.testing import (
+    login_celebrity,
+    login_person,
+    TestCaseWithFactory,
+    )
+
+
+class AffectsEmailCommandTestCase(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def test__splitPath_with_slashes(self):
+        self.assertEqual(
+            ('foo', 'bar/baz'), AffectsEmailCommand._splitPath('foo/bar/baz'))
+
+    def test__splitPath_no_slashes(self):
+        self.assertEqual(
+            ('foo', ''), AffectsEmailCommand._splitPath('foo'))
+
+    def test__normalizePath_leading_slash(self):
+        self.assertEqual(
+            'foo/bar', AffectsEmailCommand._normalizePath('/foo/bar'))
+
+    def test__normalizePath_distros(self):
+        self.assertEqual(
+            'foo/bar', AffectsEmailCommand._normalizePath('/distros/foo/bar'))
+
+    def test__normalizePath_products(self):
+        self.assertEqual(
+            'foo/bar',
+            AffectsEmailCommand._normalizePath('/products/foo/bar'))
+
+    def test_getBugTarget_no_pillar_error(self):
+        message = "There is no project named 'fnord' registered in Launchpad."
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord')
+
+    def test_getBugTarget_project_group_error(self):
+        owner = self.factory.makePerson()
+        login_person(owner)
+        project_group = self.factory.makeProject(name='fnord', owner=owner)
+        project_1 = self.factory.makeProduct(name='pting', owner=owner)
+        project_1.project = project_group
+        project_2 = self.factory.makeProduct(name='snarf', owner=owner)
+        project_2.project = project_group
+        message = (
+            "fnord is a group of projects. To report a bug, you need to "
+            "specify which of these projects the bug applies to: "
+            "pting, snarf")
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord')
+
+    def test_getBugTarget_deactivated_project_error(self):
+        project = self.factory.makeProduct(name='fnord')
+        login_celebrity('admin')
+        project.active = False
+        message = "There is no project named 'fnord' registered in Launchpad."
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord')
+
+    def test_getBugTarget_project(self):
+        project = self.factory.makeProduct(name='fnord')
+        self.assertEqual(project, AffectsEmailCommand.getBugTarget('fnord'))
+
+    def test_getBugTarget_no_project_series_error(self):
+        self.factory.makeProduct(name='fnord')
+        message = "Fnord doesn't have a series named 'pting'."
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord/pting')
+
+    def test_getBugTarget_project_series(self):
+        project = self.factory.makeProduct(name='fnord')
+        series = self.factory.makeProductSeries(name='pting', product=project)
+        self.assertEqual(
+            series, AffectsEmailCommand.getBugTarget('fnord/pting'))
+
+    def test_getBugTarget_product_extra_path_error(self):
+        product = self.factory.makeProduct(name='fnord')
+        self.factory.makeProductSeries(name='pting', product=product)
+        message = "Unexpected path components: snarf"
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord/pting/snarf')
+
+    def test_getBugTarget_no_series_or_package_error(self):
+        self.factory.makeDistribution(name='fnord')
+        message = (
+            "Fnord doesn't have a series or source package named 'pting'.")
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord/pting')
+
+    def test_getBugTarget_distribution(self):
+        distribution = self.factory.makeDistribution(name='fnord')
+        self.assertEqual(
+            distribution, AffectsEmailCommand.getBugTarget('fnord'))
+
+    def test_getBugTarget_distroseries(self):
+        distribution = self.factory.makeDistribution(name='fnord')
+        series = self.factory.makeDistroSeries(
+            name='pting', distribution=distribution)
+        self.assertEqual(
+            series, AffectsEmailCommand.getBugTarget('fnord/pting'))
+
+    def test_getBugTarget_source_package(self):
+        distribution = self.factory.makeDistribution(name='fnord')
+        series = self.factory.makeDistroSeries(
+            name='pting', distribution=distribution)
+        package = self.factory.makeSourcePackage(
+            sourcepackagename='snarf', distroseries=series, publish=True)
+        self.assertEqual(
+            package, AffectsEmailCommand.getBugTarget('fnord/pting/snarf'))
+
+    def test_getBugTarget_distribution_source_package(self):
+        distribution = self.factory.makeDistribution(name='fnord')
+        series = self.factory.makeDistroSeries(
+            name='pting', distribution=distribution)
+        package = self.factory.makeSourcePackage(
+            sourcepackagename='snarf', distroseries=series, publish=True)
+        dsp = distribution.getSourcePackage(package.name)
+        self.assertEqual(
+            dsp, AffectsEmailCommand.getBugTarget('fnord/snarf'))
+
+    def test_getBugTarget_distribution_extra_path_error(self):
+        distribution = self.factory.makeDistribution(name='fnord')
+        series = self.factory.makeDistroSeries(
+            name='pting', distribution=distribution)
+        self.factory.makeSourcePackage(
+            sourcepackagename='snarf', distroseries=series, publish=True)
+        message = "Unexpected path components: thrup"
+        self.assertRaisesWithContent(
+            BugTargetNotFound, message,
+            AffectsEmailCommand.getBugTarget, 'fnord/pting/snarf/thrup')