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
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2011-09-12 20:27:32 +0000
+++ lib/lp/bugs/model/bugtask.py 2011-09-13 21:22:25 +0000
@@ -1694,17 +1694,21 @@
1694 status_clause = (1694 status_clause = (
1695 '(BugTask.status = %s) ' %1695 '(BugTask.status = %s) ' %
1696 sqlvalues(BugTaskStatus.INCOMPLETE))1696 sqlvalues(BugTaskStatus.INCOMPLETE))
1697 # The date_last_message is fudged by one minute for
1698 # with_response and without_response to not consider changes
1699 # made at about the same time as responses. See Bug 828572
1700 # for more details.
1697 if with_response:1701 if with_response:
1698 status_clause += ("""1702 status_clause += ("""
1699 AND (Bug.date_last_message IS NOT NULL1703 AND (Bug.date_last_message IS NOT NULL
1700 AND BugTask.date_incomplete <=1704 AND BugTask.date_incomplete <=
1701 Bug.date_last_message)1705 Bug.date_last_message - interval '1 minute')
1702 """)1706 """)
1703 elif without_response:1707 elif without_response:
1704 status_clause += ("""1708 status_clause += ("""
1705 AND (Bug.date_last_message IS NULL1709 AND (Bug.date_last_message IS NULL
1706 OR BugTask.date_incomplete >1710 OR BugTask.date_incomplete >
1707 Bug.date_last_message)1711 Bug.date_last_message - interval '1 minute')
1708 """)1712 """)
1709 else:1713 else:
1710 assert with_response != without_response1714 assert with_response != without_response
17111715
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2011-09-12 20:27:32 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2011-09-13 21:22:25 +0000
@@ -32,6 +32,7 @@
32 BugTaskImportance,32 BugTaskImportance,
33 BugTaskSearchParams,33 BugTaskSearchParams,
34 BugTaskStatus,34 BugTaskStatus,
35 BugTaskStatusSearch,
35 IBugTaskSet,36 IBugTaskSet,
36 RESOLVED_BUGTASK_STATUSES,37 RESOLVED_BUGTASK_STATUSES,
37 UNRESOLVED_BUGTASK_STATUSES,38 UNRESOLVED_BUGTASK_STATUSES,
@@ -1008,6 +1009,68 @@
1008 result = target.searchTasks(None, created_since=date)1009 result = target.searchTasks(None, created_since=date)
1009 self.assertEqual([task2], list(result))1010 self.assertEqual([task2], list(result))
10101011
1012 def _setupIncompleteBugTask(self):
1013 target = self.makeBugTarget()
1014 self.login()
1015 task = self.factory.makeBugTask(target=target)
1016 bug = task.bug
1017 task.transitionToStatus(BugTaskStatus.INCOMPLETE, bug.owner)
1018 return target, task, bug
1019
1020 def test_incomplete_with_response_none_found(self):
1021 target, task, bug = self._setupIncompleteBugTask()
1022 btsp = BugTaskSearchParams(
1023 bug.owner,
1024 status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
1025 result = target.searchTasks(btsp)
1026 self.assertEqual([], list(result))
1027
1028 def test_incomplete_with_response_ignores_immediate_changes(self):
1029 target, task, bug = self._setupIncompleteBugTask()
1030 bug.tags = 'escalated'
1031 btsp = BugTaskSearchParams(
1032 bug.owner,
1033 status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
1034 result = target.searchTasks(btsp)
1035 self.assertEqual([], list(result))
1036
1037 def test_incomplete_with_response_added(self):
1038 target, task, bug = self._setupIncompleteBugTask()
1039 bug.tags = 'escalated'
1040 removeSecurityProxy(bug).date_last_message += timedelta(seconds=65)
1041 btsp = BugTaskSearchParams(
1042 bug.owner,
1043 status=BugTaskStatusSearch.INCOMPLETE_WITH_RESPONSE)
1044 result = target.searchTasks(btsp)
1045 self.assertEqual([task], list(result))
1046
1047 def test_incomplete_without_response_none_found(self):
1048 target, task, bug = self._setupIncompleteBugTask()
1049 btsp = BugTaskSearchParams(
1050 bug.owner,
1051 status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
1052 result = target.searchTasks(btsp)
1053 self.assertEqual([task], list(result))
1054
1055 def test_incomplete_without_response_ignores_immediate_change(self):
1056 target, task, bug = self._setupIncompleteBugTask()
1057 bug.tags = 'escalated'
1058 btsp = BugTaskSearchParams(
1059 bug.owner,
1060 status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
1061 result = target.searchTasks(btsp)
1062 self.assertEqual([task], list(result))
1063
1064 def test_incomplete_without_response_one_added(self):
1065 target, task, bug = self._setupIncompleteBugTask()
1066 bug.tags = 'escalated'
1067 removeSecurityProxy(bug).date_last_message += timedelta(seconds=65)
1068 btsp = BugTaskSearchParams(
1069 bug.owner,
1070 status=BugTaskStatusSearch.INCOMPLETE_WITHOUT_RESPONSE)
1071 result = target.searchTasks(btsp)
1072 self.assertEqual([], list(result))
1073
10111074
1012class BugTaskSetSearchTest(TestCaseWithFactory):1075class BugTaskSetSearchTest(TestCaseWithFactory):
10131076