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
1=== modified file 'lib/lp/bugs/browser/tests/test_bugs.py'
2--- lib/lp/bugs/browser/tests/test_bugs.py 2012-08-06 02:54:11 +0000
3+++ lib/lp/bugs/browser/tests/test_bugs.py 2012-08-07 22:53:18 +0000
4@@ -13,6 +13,7 @@
5 from lp.bugs.interfaces.malone import IMaloneApplication
6 from lp.bugs.publisher import BugsLayer
7 from lp.registry.enums import InformationType
8+from lp.registry.interfaces.product import License
9 from lp.services.webapp.publisher import canonical_url
10 from lp.testing import (
11 celebrity_logged_in,
12@@ -153,3 +154,43 @@
13 # The getBugData method works as expected if related bug is specified.
14 related_bug = self.factory.makeBug()
15 self._assert_getBugData(related_bug)
16+
17+ def test_createBug_default_private_bugs_true(self):
18+ # createBug() does not adapt the default kwargs when they are none.
19+ project = self.factory.makeProduct(
20+ licenses=[License.OTHER_PROPRIETARY])
21+ with person_logged_in(project.owner):
22+ project.setPrivateBugs(True, project.owner)
23+ bug = self.application.createBug(
24+ project.owner, 'title', 'description', project)
25+ self.assertEqual(InformationType.USERDATA, bug.information_type)
26+
27+ def test_createBug_public_bug_private_bugs_true(self):
28+ # createBug() adapts a kwarg to InformationType if one is is not None.
29+ project = self.factory.makeProduct(
30+ licenses=[License.OTHER_PROPRIETARY])
31+ with person_logged_in(project.owner):
32+ project.setPrivateBugs(True, project.owner)
33+ bug = self.application.createBug(
34+ project.owner, 'title', 'description', project, private=False)
35+ self.assertEqual(InformationType.PUBLIC, bug.information_type)
36+
37+ def test_createBug_default_private_bugs_false(self):
38+ # createBug() does not adapt the default kwargs when they are none.
39+ project = self.factory.makeProduct(
40+ licenses=[License.OTHER_PROPRIETARY])
41+ with person_logged_in(project.owner):
42+ project.setPrivateBugs(False, project.owner)
43+ bug = self.application.createBug(
44+ project.owner, 'title', 'description', project)
45+ self.assertEqual(InformationType.PUBLIC, bug.information_type)
46+
47+ def test_createBug_private_bug_private_bugs_false(self):
48+ # createBug() adapts a kwarg to InformationType if one is is not None.
49+ project = self.factory.makeProduct(
50+ licenses=[License.OTHER_PROPRIETARY])
51+ with person_logged_in(project.owner):
52+ project.setPrivateBugs(False, project.owner)
53+ bug = self.application.createBug(
54+ project.owner, 'title', 'description', project, private=True)
55+ self.assertEqual(InformationType.USERDATA, bug.information_type)
56
57=== modified file 'lib/lp/bugs/interfaces/malone.py'
58--- lib/lp/bugs/interfaces/malone.py 2012-08-06 02:54:11 +0000
59+++ lib/lp/bugs/interfaces/malone.py 2012-08-07 22:53:18 +0000
60@@ -74,11 +74,13 @@
61 target=Reference(
62 schema=IBugTarget, required=True,
63 title=u"The project, distribution or source package that has "
64- "this bug."))
65+ "this bug."),
66+ security_related=copy_field(IBug['security_related'], default=None),
67+ private=copy_field(IBug['private'], default=None))
68 @export_factory_operation(
69- IBug, ['title', 'description', 'tags', 'security_related', 'private'])
70- def createBug(owner, title, description, target, security_related=False,
71- private=False, tags=None):
72+ IBug, ['title', 'description', 'tags'])
73+ def createBug(owner, title, description, target, security_related=None,
74+ private=None, tags=None):
75 """Create a bug (with an appropriate bugtask) and return it.
76
77 :param target: The Product, Distribution or DistributionSourcePackage
78
79=== modified file 'lib/lp/bugs/tests/test_bugs_webservice.py'
80--- lib/lp/bugs/tests/test_bugs_webservice.py 2012-07-07 15:26:29 +0000
81+++ lib/lp/bugs/tests/test_bugs_webservice.py 2012-08-07 22:53:18 +0000
82@@ -24,6 +24,7 @@
83 from lp.bugs.browser.bugtask import get_comments_for_bugtask
84 from lp.bugs.interfaces.bug import IBug
85 from lp.registry.enums import InformationType
86+from lp.registry.interfaces.product import License
87 from lp.services.webapp import snapshot
88 from lp.services.webapp.servers import LaunchpadTestRequest
89 from lp.testing import (
90@@ -32,6 +33,7 @@
91 login,
92 login_person,
93 logout,
94+ person_logged_in,
95 TestCaseWithFactory,
96 )
97 from lp.testing._webservice import QueryCollector
98@@ -363,3 +365,37 @@
99 lp_bug = launchpad.load(api_url(bug))
100 self.assertRaises(
101 BadRequest, lp_bug.addTask, target=api_url(product))
102+
103+
104+class BugSetTestCase(TestCaseWithFactory):
105+
106+ layer = DatabaseFunctionalLayer
107+
108+ def test_default_private_bugs_true(self):
109+ # Verify the path through user submission, to MaloneApplication to
110+ # BugSet, and back to the user creates a private bug according
111+ # to the project's bugs are private by default rule.
112+ project = self.factory.makeProduct(
113+ licenses=[License.OTHER_PROPRIETARY])
114+ with person_logged_in(project.owner):
115+ project.setPrivateBugs(True, project.owner)
116+ webservice = launchpadlib_for('test', 'salgado')
117+ bugs_collection = webservice.load('/bugs')
118+ bug = bugs_collection.createBug(
119+ target=api_url(project), title='title', description='desc')
120+ self.assertEqual('Private', bug.information_type)
121+
122+ def test_explicit_private_private_bugs_true(self):
123+ # Verify the path through user submission, to MaloneApplication to
124+ # BugSet, and back to the user creates a private bug beause the
125+ # user commands it.
126+ project = self.factory.makeProduct(
127+ licenses=[License.OTHER_PROPRIETARY])
128+ with person_logged_in(project.owner):
129+ project.setPrivateBugs(True, project.owner)
130+ webservice = launchpadlib_for('test', 'salgado')
131+ bugs_collection = webservice.load('/bugs')
132+ bug = bugs_collection.createBug(
133+ target=api_url(project), title='title', description='desc',
134+ private=True)
135+ self.assertEqual('Private', bug.information_type)
136
137=== modified file 'lib/lp/systemhomes.py'
138--- lib/lp/systemhomes.py 2012-08-07 08:18:39 +0000
139+++ lib/lp/systemhomes.py 2012-08-07 22:53:18 +0000
140@@ -155,10 +155,14 @@
141 return data
142
143 def createBug(self, owner, title, description, target,
144- security_related=False, private=False, tags=None):
145+ security_related=None, private=None, tags=None):
146 """See `IMaloneApplication`."""
147- information_type = convert_to_information_type(
148- private, security_related)
149+ if security_related is None and private is None:
150+ # Nothing to adapt, let BugSet.createBug() choose the default.
151+ information_type = None
152+ else:
153+ information_type = convert_to_information_type(
154+ private, security_related)
155 params = CreateBugParams(
156 title=title, comment=description, owner=owner,
157 information_type=information_type, tags=tags)