Merge lp:~sinzui/launchpad/default-private-bug-damnit into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 15761
Proposed branch: lp:~sinzui/launchpad/default-private-bug-damnit
Merge into: lp:launchpad
Diff against target: 157 lines (+90/-7)
4 files modified
lib/lp/bugs/browser/tests/test_bugs.py (+41/-0)
lib/lp/bugs/interfaces/malone.py (+6/-4)
lib/lp/bugs/tests/test_bugs_webservice.py (+36/-0)
lib/lp/systemhomes.py (+7/-3)
To merge this branch: bzr merge lp:~sinzui/launchpad/default-private-bug-damnit
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+118644@code.launchpad.net

Commit message

Honour what the user submits (and the project's default privacy bugs rule) when creating bugs via the API.

Description of the change

A recent attempt to refactor and normalise the bug creation rules causes
all bugs created of the API to be public if no private or security bools
are passed. The bug creation rules do not respect the default private
bug creation rules of the project.

--------------------------------------------------------------------

RULES

    Pre-implementation: no one
    * Locate the existing test that shows bugs created via the API honour
      the default private bugs rules
      * Damn it. Write one (again!)
    * BugSet.createBug() is getting InformationType.PUBLIC even when
      InformationType or the old private/security bools are not passed.
    * lp.systemhomes.MaloneApplication.createBug() adapts the private and
      security bools to InformationType. The method sets the default values
      for private/security to False/False; manufacturing user submitted
      data for BugSet.createBug().
      * Only adapt private/security if the user submits the information.
        BugSet.createBug() knows how to handle information_type == None
        and will apply the projects default rules.

QA

    * Run this function against qastaging:
        def test_default_private():
            lp = Launchpad.login_with(
                'testing', service_root='https://api.qastaging.launchpad.net',
                version='devel')
            project = lp.projects['sutton']
            lp.bugs.createBug(
                target=project,
                title='testing bug creation via API',
                description="testing that the bug is private by default.")
    * Verify the bug is private.
    * Run this function against qastaging:
        def test_force_public():
            lp = Launchpad.login_with(
                'testing', service_root='https://api.qastaging.launchpad.net',
                version='devel')
            project = lp.projects['sutton']
            lp.bugs.createBug(
                target=project,
                title='testing bug creation via API',
                description="testing that the bug is force to public."
                public=True)
    * Verify the bug is public.

LINT

    lib/lp/systemhomes.py
    lib/lp/bugs/browser/tests/test_bugs.py
    lib/lp/bugs/interfaces/malone.py
    lib/lp/bugs/tests/test_bugs_webservice.py

TEST

    ./bin/test -vvc -t TestMaloneView lp.bugs.browser.tests.test_bugs
    ./bin/test -vvc -t BugSetTestCase lp.bugs.tests.test_bugs_webservice

IMPLEMENTATION

Updated MaloneApplication.createBug() to only adapt the private and security
kwargs if they are provided. Let BugSet.createBug() the bug using the
project's rules for default bug creation.
    lib/lp/systemhomes.py
    lib/lp/bugs/browser/tests/test_bugs.py

Update the exported createBug() to permit default None so that Lp does not
tamper with the data the user submits. Added an integration test to ensure
This rule does not break again.
    lib/lp/bugs/interfaces/malone.py
    lib/lp/bugs/tests/test_bugs_webservice.py

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/browser/tests/test_bugs.py'
--- lib/lp/bugs/browser/tests/test_bugs.py 2012-08-06 02:54:11 +0000
+++ lib/lp/bugs/browser/tests/test_bugs.py 2012-08-07 22:53:18 +0000
@@ -13,6 +13,7 @@
13from lp.bugs.interfaces.malone import IMaloneApplication13from lp.bugs.interfaces.malone import IMaloneApplication
14from lp.bugs.publisher import BugsLayer14from lp.bugs.publisher import BugsLayer
15from lp.registry.enums import InformationType15from lp.registry.enums import InformationType
16from lp.registry.interfaces.product import License
16from lp.services.webapp.publisher import canonical_url17from lp.services.webapp.publisher import canonical_url
17from lp.testing import (18from lp.testing import (
18 celebrity_logged_in,19 celebrity_logged_in,
@@ -153,3 +154,43 @@
153 # The getBugData method works as expected if related bug is specified.154 # The getBugData method works as expected if related bug is specified.
154 related_bug = self.factory.makeBug()155 related_bug = self.factory.makeBug()
155 self._assert_getBugData(related_bug)156 self._assert_getBugData(related_bug)
157
158 def test_createBug_default_private_bugs_true(self):
159 # createBug() does not adapt the default kwargs when they are none.
160 project = self.factory.makeProduct(
161 licenses=[License.OTHER_PROPRIETARY])
162 with person_logged_in(project.owner):
163 project.setPrivateBugs(True, project.owner)
164 bug = self.application.createBug(
165 project.owner, 'title', 'description', project)
166 self.assertEqual(InformationType.USERDATA, bug.information_type)
167
168 def test_createBug_public_bug_private_bugs_true(self):
169 # createBug() adapts a kwarg to InformationType if one is is not None.
170 project = self.factory.makeProduct(
171 licenses=[License.OTHER_PROPRIETARY])
172 with person_logged_in(project.owner):
173 project.setPrivateBugs(True, project.owner)
174 bug = self.application.createBug(
175 project.owner, 'title', 'description', project, private=False)
176 self.assertEqual(InformationType.PUBLIC, bug.information_type)
177
178 def test_createBug_default_private_bugs_false(self):
179 # createBug() does not adapt the default kwargs when they are none.
180 project = self.factory.makeProduct(
181 licenses=[License.OTHER_PROPRIETARY])
182 with person_logged_in(project.owner):
183 project.setPrivateBugs(False, project.owner)
184 bug = self.application.createBug(
185 project.owner, 'title', 'description', project)
186 self.assertEqual(InformationType.PUBLIC, bug.information_type)
187
188 def test_createBug_private_bug_private_bugs_false(self):
189 # createBug() adapts a kwarg to InformationType if one is is not None.
190 project = self.factory.makeProduct(
191 licenses=[License.OTHER_PROPRIETARY])
192 with person_logged_in(project.owner):
193 project.setPrivateBugs(False, project.owner)
194 bug = self.application.createBug(
195 project.owner, 'title', 'description', project, private=True)
196 self.assertEqual(InformationType.USERDATA, bug.information_type)
156197
=== modified file 'lib/lp/bugs/interfaces/malone.py'
--- lib/lp/bugs/interfaces/malone.py 2012-08-06 02:54:11 +0000
+++ lib/lp/bugs/interfaces/malone.py 2012-08-07 22:53:18 +0000
@@ -74,11 +74,13 @@
74 target=Reference(74 target=Reference(
75 schema=IBugTarget, required=True,75 schema=IBugTarget, required=True,
76 title=u"The project, distribution or source package that has "76 title=u"The project, distribution or source package that has "
77 "this bug."))77 "this bug."),
78 security_related=copy_field(IBug['security_related'], default=None),
79 private=copy_field(IBug['private'], default=None))
78 @export_factory_operation(80 @export_factory_operation(
79 IBug, ['title', 'description', 'tags', 'security_related', 'private'])81 IBug, ['title', 'description', 'tags'])
80 def createBug(owner, title, description, target, security_related=False,82 def createBug(owner, title, description, target, security_related=None,
81 private=False, tags=None):83 private=None, tags=None):
82 """Create a bug (with an appropriate bugtask) and return it.84 """Create a bug (with an appropriate bugtask) and return it.
8385
84 :param target: The Product, Distribution or DistributionSourcePackage86 :param target: The Product, Distribution or DistributionSourcePackage
8587
=== modified file 'lib/lp/bugs/tests/test_bugs_webservice.py'
--- lib/lp/bugs/tests/test_bugs_webservice.py 2012-07-07 15:26:29 +0000
+++ lib/lp/bugs/tests/test_bugs_webservice.py 2012-08-07 22:53:18 +0000
@@ -24,6 +24,7 @@
24from lp.bugs.browser.bugtask import get_comments_for_bugtask24from lp.bugs.browser.bugtask import get_comments_for_bugtask
25from lp.bugs.interfaces.bug import IBug25from lp.bugs.interfaces.bug import IBug
26from lp.registry.enums import InformationType26from lp.registry.enums import InformationType
27from lp.registry.interfaces.product import License
27from lp.services.webapp import snapshot28from lp.services.webapp import snapshot
28from lp.services.webapp.servers import LaunchpadTestRequest29from lp.services.webapp.servers import LaunchpadTestRequest
29from lp.testing import (30from lp.testing import (
@@ -32,6 +33,7 @@
32 login,33 login,
33 login_person,34 login_person,
34 logout,35 logout,
36 person_logged_in,
35 TestCaseWithFactory,37 TestCaseWithFactory,
36 )38 )
37from lp.testing._webservice import QueryCollector39from lp.testing._webservice import QueryCollector
@@ -363,3 +365,37 @@
363 lp_bug = launchpad.load(api_url(bug))365 lp_bug = launchpad.load(api_url(bug))
364 self.assertRaises(366 self.assertRaises(
365 BadRequest, lp_bug.addTask, target=api_url(product))367 BadRequest, lp_bug.addTask, target=api_url(product))
368
369
370class BugSetTestCase(TestCaseWithFactory):
371
372 layer = DatabaseFunctionalLayer
373
374 def test_default_private_bugs_true(self):
375 # Verify the path through user submission, to MaloneApplication to
376 # BugSet, and back to the user creates a private bug according
377 # to the project's bugs are private by default rule.
378 project = self.factory.makeProduct(
379 licenses=[License.OTHER_PROPRIETARY])
380 with person_logged_in(project.owner):
381 project.setPrivateBugs(True, project.owner)
382 webservice = launchpadlib_for('test', 'salgado')
383 bugs_collection = webservice.load('/bugs')
384 bug = bugs_collection.createBug(
385 target=api_url(project), title='title', description='desc')
386 self.assertEqual('Private', bug.information_type)
387
388 def test_explicit_private_private_bugs_true(self):
389 # Verify the path through user submission, to MaloneApplication to
390 # BugSet, and back to the user creates a private bug beause the
391 # user commands it.
392 project = self.factory.makeProduct(
393 licenses=[License.OTHER_PROPRIETARY])
394 with person_logged_in(project.owner):
395 project.setPrivateBugs(True, project.owner)
396 webservice = launchpadlib_for('test', 'salgado')
397 bugs_collection = webservice.load('/bugs')
398 bug = bugs_collection.createBug(
399 target=api_url(project), title='title', description='desc',
400 private=True)
401 self.assertEqual('Private', bug.information_type)
366402
=== modified file 'lib/lp/systemhomes.py'
--- lib/lp/systemhomes.py 2012-08-07 08:18:39 +0000
+++ lib/lp/systemhomes.py 2012-08-07 22:53:18 +0000
@@ -155,10 +155,14 @@
155 return data155 return data
156156
157 def createBug(self, owner, title, description, target,157 def createBug(self, owner, title, description, target,
158 security_related=False, private=False, tags=None):158 security_related=None, private=None, tags=None):
159 """See `IMaloneApplication`."""159 """See `IMaloneApplication`."""
160 information_type = convert_to_information_type(160 if security_related is None and private is None:
161 private, security_related)161 # Nothing to adapt, let BugSet.createBug() choose the default.
162 information_type = None
163 else:
164 information_type = convert_to_information_type(
165 private, security_related)
162 params = CreateBugParams(166 params = CreateBugParams(
163 title=title, comment=description, owner=owner,167 title=title, comment=description, owner=owner,
164 information_type=information_type, tags=tags)168 information_type=information_type, tags=tags)