Merge lp:~wgrant/launchpad/complete-incomplete into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 18037
Proposed branch: lp:~wgrant/launchpad/complete-incomplete
Merge into: lp:launchpad
Diff against target: 197 lines (+91/-16)
4 files modified
lib/lp/bugs/model/bugtask.py (+16/-10)
lib/lp/bugs/model/tests/test_bugtask.py (+16/-1)
lib/lp/bugs/tests/test_bug_messages.py (+51/-1)
lib/lp/testing/factory.py (+8/-4)
To merge this branch: bzr merge lp:~wgrant/launchpad/complete-incomplete
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+293859@code.launchpad.net

Commit message

Fix BugTaskSet.createManyTasks to map Incomplete to its storage values.

Description of the change

Fix BugTaskSet.createManyTasks to map Incomplete to its storage values.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/model/bugtask.py'
2--- lib/lp/bugs/model/bugtask.py 2015-09-28 12:25:52 +0000
3+++ lib/lp/bugs/model/bugtask.py 2016-05-05 08:25:25 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Classes that implement IBugTask and its related interfaces."""
10@@ -302,6 +302,19 @@
11 return value
12
13
14+def map_status_for_storage(bug, status, when=None):
15+ if status == BugTaskStatus.INCOMPLETE:
16+ # We store INCOMPLETE as INCOMPLETE_WITHOUT_RESPONSE so that it
17+ # can be queried on efficiently.
18+ if (when is None or bug.date_last_message is None or
19+ when > bug.date_last_message):
20+ return BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE
21+ else:
22+ return BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE
23+ else:
24+ return status
25+
26+
27 def validate_assignee(self, attr, value):
28 value = validate_conjoined_attribute(self, attr, value)
29 # Check if this person is valid and not None.
30@@ -868,15 +881,7 @@
31 "Only Bug Supervisors may change status to %s." % (
32 new_status.title,))
33
34- if new_status == BugTaskStatus.INCOMPLETE:
35- # We store INCOMPLETE as INCOMPLETE_WITHOUT_RESPONSE so that it
36- # can be queried on efficiently.
37- if (when is None or self.bug.date_last_message is None or
38- when > self.bug.date_last_message):
39- new_status = BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE
40- else:
41- new_status = BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE
42-
43+ new_status = map_status_for_storage(self.bug, new_status, when=when)
44 self._setStatusDateProperties(self.status, new_status, when=when)
45
46 def _setStatusDateProperties(self, old_status, new_status, when=None):
47@@ -1573,6 +1578,7 @@
48 """See `IBugTaskSet`."""
49 if status is None:
50 status = IBugTask['status'].default
51+ status = map_status_for_storage(bug, status)
52 if importance is None:
53 importance = IBugTask['importance'].default
54 target_keys = []
55
56=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
57--- lib/lp/bugs/model/tests/test_bugtask.py 2016-01-26 15:47:37 +0000
58+++ lib/lp/bugs/model/tests/test_bugtask.py 2016-05-05 08:25:25 +0000
59@@ -1,4 +1,4 @@
60-# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
61+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
62 # GNU Affero General Public License version 3 (see the file LICENSE).
63
64 __metaclass__ = type
65@@ -224,6 +224,21 @@
66 self.assertContentEqual(
67 expected_policies, get_policies_for_artifact(bug))
68
69+ def test_incomplete_mapped_for_storage(self):
70+ """A task is never actually "Incomplete" in the DB.
71+
72+ Incomplete is automatically mapped to (with response) or
73+ (without response) as appropriate.
74+ """
75+ task = getUtility(IBugTaskSet).createTask(
76+ self.factory.makeBug(), self.factory.makePerson(),
77+ self.factory.makeProduct(),
78+ status=BugTaskStatus.INCOMPLETE)
79+ self.assertEqual(
80+ BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE, task._status)
81+ self.assertEqual(
82+ BugTaskStatus.INCOMPLETE, task.status)
83+
84
85 class TestBugTaskCreationPackageComponent(TestCaseWithFactory):
86 """IBugTask contains a convenience method to look up archive component
87
88=== modified file 'lib/lp/bugs/tests/test_bug_messages.py'
89--- lib/lp/bugs/tests/test_bug_messages.py 2012-09-18 18:36:09 +0000
90+++ lib/lp/bugs/tests/test_bug_messages.py 2016-05-05 08:25:25 +0000
91@@ -1,4 +1,4 @@
92-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
93+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
94 # GNU Affero General Public License version 3 (see the file LICENSE).
95
96 """Webservice unit tests related to Launchpad Bugs."""
97@@ -8,10 +8,15 @@
98 from zope.component import getUtility
99
100 from lp.app.enums import InformationType
101+from lp.bugs.interfaces.bugtask import (
102+ BugTaskStatus,
103+ BugTaskStatusSearch,
104+ )
105 from lp.registry.interfaces.accesspolicy import IAccessPolicySource
106 from lp.testing import (
107 login,
108 login_celebrity,
109+ person_logged_in,
110 TestCaseWithFactory,
111 )
112 from lp.testing.layers import DatabaseFunctionalLayer
113@@ -77,3 +82,48 @@
114 self.factory.makeAccessPolicyGrant(
115 policy=policy, grantor=product.owner, grantee=person)
116 self.assertTrue(bug.userCanSetCommentVisibility(person))
117+
118+
119+class TestBugLinkMessageSetsIncompleteStatus(TestCaseWithFactory):
120+
121+ """Test that Bug.linkMessage updates "Incomplete (without response)" bugs.
122+
123+ They should transition from "Incomplete (without response)" to
124+ "Incomplete (with response)".
125+ """
126+
127+ layer = DatabaseFunctionalLayer
128+
129+ def test_new_untouched(self):
130+ bugtask = self.factory.makeBugTask(status=BugTaskStatus.NEW)
131+ with person_logged_in(bugtask.owner):
132+ bugtask.bug.linkMessage(self.factory.makeMessage())
133+ self.assertEqual(BugTaskStatus.NEW, bugtask.status)
134+
135+ def test_incomplete_with_response_untouched(self):
136+ bugtask = self.factory.makeBugTask(
137+ status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
138+ self.assertEqual(
139+ BugTaskStatus.INCOMPLETE, bugtask.status)
140+ self.assertEqual(
141+ BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE, bugtask._status)
142+ with person_logged_in(bugtask.owner):
143+ bugtask.bug.linkMessage(self.factory.makeMessage())
144+ self.assertEqual(
145+ BugTaskStatus.INCOMPLETE, bugtask.status)
146+ self.assertEqual(
147+ BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE, bugtask._status)
148+
149+ def test_incomplete_without_response_updated(self):
150+ bugtask = self.factory.makeBugTask(
151+ status=BugTaskStatus.INCOMPLETE)
152+ self.assertEqual(
153+ BugTaskStatus.INCOMPLETE, bugtask.status)
154+ self.assertEqual(
155+ BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE, bugtask._status)
156+ with person_logged_in(bugtask.owner):
157+ bugtask.bug.linkMessage(self.factory.makeMessage())
158+ self.assertEqual(
159+ BugTaskStatus.INCOMPLETE, bugtask.status)
160+ self.assertEqual(
161+ BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE, bugtask._status)
162
163=== modified file 'lib/lp/testing/factory.py'
164--- lib/lp/testing/factory.py 2016-04-28 02:25:46 +0000
165+++ lib/lp/testing/factory.py 2016-05-05 08:25:25 +0000
166@@ -83,7 +83,10 @@
167 CreateBugParams,
168 IBugSet,
169 )
170-from lp.bugs.interfaces.bugtask import BugTaskStatus
171+from lp.bugs.interfaces.bugtask import (
172+ BugTaskStatus,
173+ IBugTaskSet,
174+ )
175 from lp.bugs.interfaces.bugtracker import (
176 BugTrackerType,
177 IBugTrackerSet,
178@@ -1875,7 +1878,8 @@
179 removeSecurityProxy(bug).clearBugNotificationRecipientsCache()
180 return bug
181
182- def makeBugTask(self, bug=None, target=None, owner=None, publish=True):
183+ def makeBugTask(self, bug=None, target=None, owner=None, publish=True,
184+ status=None):
185 """Create and return a bug task.
186
187 If the bug is already targeted to the given target, the existing
188@@ -1944,8 +1948,8 @@
189
190 if owner is None:
191 owner = self.makePerson()
192- task = removeSecurityProxy(bug).addTask(
193- owner, removeSecurityProxy(target))
194+ task = getUtility(IBugTaskSet).createTask(
195+ bug, owner, target, status=status)
196 removeSecurityProxy(bug).clearBugNotificationRecipientsCache()
197 return task
198