Merge lp:~bac/launchpad/bug-828572 into lp:launchpad

Proposed by Brad Crittenden
Status: Rejected
Rejected by: Brad Crittenden
Proposed branch: lp:~bac/launchpad/bug-828572
Merge into: lp:launchpad
Diff against target: 107 lines (+69/-2)
2 files modified
lib/lp/bugs/model/bugtask.py (+6/-2)
lib/lp/bugs/model/tests/test_bugtask.py (+63/-0)
To merge this branch: bzr merge lp:~bac/launchpad/bug-828572
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) Needs Fixing
j.c.sackett (community) Approve
Review via email: mp+75263@code.launchpad.net

Commit message

[r=jcsackett][bug=828572] Changes to a bug task immediately (< 1 minute) after marking it incomplete no longer count as a response.

Description of the change

= Summary =

Changes to a bug task immediately (< 1 minute) after marking it
incomplete should not count as a response.

== Proposed fix ==

Put in time interval tweaks in the query.

== Pre-implementation notes ==

None

== Implementation details ==

As above

== Tests ==

bin/test -vvm lp.bugs -t test_incomplete

== Demo and Q/A ==

Mark bug task incomplete. Within a minute add a tag. See that
searches for WITH and WITHOUT RESPONSES work.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/model/tests/test_bugtask.py
  lib/lp/bugs/model/bugtask.py

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

This looks fine.

review: Approve
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Hi Brad,

Thanks for working on this stakeholders' escalated bug.

You didn't list anybody in the Pre-implementation section, did you discuss with anyone if this change would be appropriate?

I fear that solution is inadequate for a few reasons:

* The original bug mention this would also affect expiration, this solution doesn't address that. (Not necessarily a big problem, you could easily file another bug about the expiration aspect.)

* If for some reason the user is available and respond within one minute, the bug will still be considered without response. That might be a corner case, but it's still possible and would result in a bug being filed.

I'd suggest approaching this from another angle: don't update date_last_message for changes that shouldn't be considered for expiration or don't really consider a response. In a way, date_last_message should only be updated for "new messages", not for status, importance, tags, or any other non-message related changes. That should solve both problems.

It would leave all existing bugs that had their date_last_message wrongly set show up in the searches. We might consider a data migration for that (update the date_last_message field based on the date of the... last message for all incomplete bug. We should do that in a garbo task.)

review: Needs Fixing
Revision history for this message
Robert Collins (lifeless) wrote :

+1 on flacostes review - I have a branch that makes the two
INCOMPLETE_WITH_RESPONSE and INCOMPLETE_WITHOUT_RESPONSE distinct
enums - so putting slack in the query will definitely not be
sufficient for this bug.

Revision history for this message
Brad Crittenden (bac) wrote :

Hi Robert,

Thanks for your comments. I'd like to see that branch you mention. Could you link it to the bug?

Unmerged revisions

13926. By Brad Crittenden

Make INCOMPLETE_WITH/OUT_RESPONSE ignore immediate changes

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 2011-09-12 20:27:32 +0000
3+++ lib/lp/bugs/model/bugtask.py 2011-09-13 21:22:25 +0000
4@@ -1694,17 +1694,21 @@
5 status_clause = (
6 '(BugTask.status = %s) ' %
7 sqlvalues(BugTaskStatus.INCOMPLETE))
8+ # The date_last_message is fudged by one minute for
9+ # with_response and without_response to not consider changes
10+ # made at about the same time as responses. See Bug 828572
11+ # for more details.
12 if with_response:
13 status_clause += ("""
14 AND (Bug.date_last_message IS NOT NULL
15 AND BugTask.date_incomplete <=
16- Bug.date_last_message)
17+ Bug.date_last_message - interval '1 minute')
18 """)
19 elif without_response:
20 status_clause += ("""
21 AND (Bug.date_last_message IS NULL
22 OR BugTask.date_incomplete >
23- Bug.date_last_message)
24+ Bug.date_last_message - interval '1 minute')
25 """)
26 else:
27 assert with_response != without_response
28
29=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
30--- lib/lp/bugs/model/tests/test_bugtask.py 2011-09-12 20:27:32 +0000
31+++ lib/lp/bugs/model/tests/test_bugtask.py 2011-09-13 21:22:25 +0000
32@@ -32,6 +32,7 @@
33 BugTaskImportance,
34 BugTaskSearchParams,
35 BugTaskStatus,
36+ BugTaskStatusSearch,
37 IBugTaskSet,
38 RESOLVED_BUGTASK_STATUSES,
39 UNRESOLVED_BUGTASK_STATUSES,
40@@ -1008,6 +1009,68 @@
41 result = target.searchTasks(None, created_since=date)
42 self.assertEqual([task2], list(result))
43
44+ def _setupIncompleteBugTask(self):
45+ target = self.makeBugTarget()
46+ self.login()
47+ task = self.factory.makeBugTask(target=target)
48+ bug = task.bug
49+ task.transitionToStatus(BugTaskStatus.INCOMPLETE, bug.owner)
50+ return target, task, bug
51+
52+ def test_incomplete_with_response_none_found(self):
53+ target, task, bug = self._setupIncompleteBugTask()
54+ btsp = BugTaskSearchParams(
55+ bug.owner,
56+ status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
57+ result = target.searchTasks(btsp)
58+ self.assertEqual([], list(result))
59+
60+ def test_incomplete_with_response_ignores_immediate_changes(self):
61+ target, task, bug = self._setupIncompleteBugTask()
62+ bug.tags = 'escalated'
63+ btsp = BugTaskSearchParams(
64+ bug.owner,
65+ status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
66+ result = target.searchTasks(btsp)
67+ self.assertEqual([], list(result))
68+
69+ def test_incomplete_with_response_added(self):
70+ target, task, bug = self._setupIncompleteBugTask()
71+ bug.tags = 'escalated'
72+ removeSecurityProxy(bug).date_last_message += timedelta(seconds=65)
73+ btsp = BugTaskSearchParams(
74+ bug.owner,
75+ status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
76+ result = target.searchTasks(btsp)
77+ self.assertEqual([task], list(result))
78+
79+ def test_incomplete_without_response_none_found(self):
80+ target, task, bug = self._setupIncompleteBugTask()
81+ btsp = BugTaskSearchParams(
82+ bug.owner,
83+ status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
84+ result = target.searchTasks(btsp)
85+ self.assertEqual([task], list(result))
86+
87+ def test_incomplete_without_response_ignores_immediate_change(self):
88+ target, task, bug = self._setupIncompleteBugTask()
89+ bug.tags = 'escalated'
90+ btsp = BugTaskSearchParams(
91+ bug.owner,
92+ status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
93+ result = target.searchTasks(btsp)
94+ self.assertEqual([task], list(result))
95+
96+ def test_incomplete_without_response_one_added(self):
97+ target, task, bug = self._setupIncompleteBugTask()
98+ bug.tags = 'escalated'
99+ removeSecurityProxy(bug).date_last_message += timedelta(seconds=65)
100+ btsp = BugTaskSearchParams(
101+ bug.owner,
102+ status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
103+ result = target.searchTasks(btsp)
104+ self.assertEqual([], list(result))
105+
106
107 class BugTaskSetSearchTest(TestCaseWithFactory):
108