1
# Copyright 2009 Canonical Ltd. This software is licensed under the
1
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
6
from datetime import datetime
13
8
from lazr.lifecycle.event import ObjectModifiedEvent
14
9
from lazr.lifecycle.snapshot import Snapshot
15
10
from pytz import UTC
16
11
from storm.store import Store
17
12
from testtools.matchers import LessThan
18
14
from zope.component import (
1047
1044
layer = LaunchpadFunctionalLayer
1049
def _makeNoisyBug(self, comments_only=False):
1046
def _makeNoisyBug(self, comments_only=False, number_of_comments=10,
1047
number_of_changes=10):
1050
1048
"""Create and return a bug with a lot of comments and activity."""
1051
bug = self.factory.makeBug(
1052
date_created=datetime.now(UTC) - timedelta(days=30))
1049
bug = self.factory.makeBug()
1053
1050
with person_logged_in(bug.owner):
1054
1051
if not comments_only:
1056
task = self.factory.makeBugTask(bug=bug)
1052
for i in range(number_of_changes):
1057
1053
change = BugTaskStatusChange(
1058
task, datetime.now(UTC), task.product.owner, 'status',
1054
bug.default_bugtask, UTC_NOW,
1055
bug.default_bugtask.product.owner, 'status',
1059
1056
BugTaskStatus.NEW, BugTaskStatus.TRIAGED)
1060
1057
bug.addChange(change)
1061
for i in range (10):
1058
for i in range(number_of_comments):
1062
1059
msg = self.factory.makeMessage(
1063
owner=bug.owner, content="Message %i." % i,
1064
datecreated=datetime.now(UTC) - timedelta(days=20-i))
1060
owner=bug.owner, content="Message %i." % i)
1065
1061
bug.linkMessage(msg, user=bug.owner)
1064
def _assertThatUnbatchedAndBatchedActivityMatch(self, unbatched_activity,
1066
zipped_activity = zip(
1067
unbatched_activity, batched_activity)
1068
for index, items in enumerate(zipped_activity):
1069
unbatched_item, batched_item = items
1071
unbatched_item['comment'].index,
1072
batched_item['comment'].index,
1073
"The comments at index %i don't match. Expected to see "
1074
"comment %i, got comment %i instead." %
1075
(index, unbatched_item['comment'].index,
1076
batched_item['comment'].index))
1068
1078
def test_offset(self):
1069
1079
# BugTaskBatchedCommentsAndActivityView.offset returns the
1070
1080
# current offset being used to select a batch of bug comments
1071
# and activity. If one is not specified, the view's
1072
# visible_initial_comments count will be returned (so that
1073
# comments already shown on the page won't appear twice).
1081
# and activity. If one is not specified, the offset will be the
1082
# view's visible_initial_comments count + 1 (so that comments
1083
# already shown on the page won't appear twice).
1074
1084
bug_task = self.factory.makeBugTask()
1075
1085
view = create_initialized_view(bug_task, '+batched-comments')
1076
self.assertEqual(view.visible_initial_comments, view.offset)
1086
self.assertEqual(view.visible_initial_comments + 1, view.offset)
1077
1087
view = create_initialized_view(
1078
1088
bug_task, '+batched-comments', form={'offset': 100})
1079
1089
self.assertEqual(100, view.offset)
1095
1105
def test_event_groups_only_returns_batch_size_results(self):
1096
1106
# BugTaskBatchedCommentsAndActivityView._event_groups will
1097
1107
# return only batch_size results.
1098
bug = self._makeNoisyBug()
1108
bug = self._makeNoisyBug(number_of_comments=20)
1099
1109
view = create_initialized_view(
1100
1110
bug.default_bugtask, '+batched-comments',
1101
form={'batch_size': 10})
1111
form={'batch_size': 10, 'offset': 1})
1102
1112
self.assertEqual(10, len([group for group in view._event_groups]))
1114
def test_event_groups_excludes_visible_recent_comments(self):
1115
# BugTaskBatchedCommentsAndActivityView._event_groups will
1116
# not return the last view comments - those covered by the
1117
# visible_recent_comments property.
1118
bug = self._makeNoisyBug(number_of_comments=20, comments_only=True)
1119
batched_view = create_initialized_view(
1120
bug.default_bugtask, '+batched-comments',
1121
form={'batch_size': 10, 'offset': 10})
1122
expected_length = 10 - batched_view.visible_recent_comments
1123
actual_length = len([group for group in batched_view._event_groups])
1125
expected_length, actual_length,
1126
"Expected %i comments, got %i." %
1127
(expected_length, actual_length))
1128
unbatched_view = create_initialized_view(
1129
bug.default_bugtask, '+index', form={'comments': 'all'})
1130
self._assertThatUnbatchedAndBatchedActivityMatch(
1131
unbatched_view.activity_and_comments[9:],
1132
batched_view.activity_and_comments)
1104
1134
def test_activity_and_comments_matches_unbatched_version(self):
1105
1135
# BugTaskBatchedCommentsAndActivityView extends BugTaskView in
1106
1136
# order to add the batching logic and reduce rendering
1109
1139
# We create a bug with comments only so that we can test the
1110
1140
# contents of activity_and_comments properly. Trying to test it
1111
1141
# with multiply different datatypes is fragile at best.
1112
bug = self._makeNoisyBug(comments_only=True)
1142
bug = self._makeNoisyBug(comments_only=True, number_of_comments=20)
1113
1143
# We create a batched view with an offset of 0 so that all the
1114
1144
# comments are returned.
1115
1145
batched_view = create_initialized_view(
1116
1146
bug.default_bugtask, '+batched-comments',
1147
{'offset': 5, 'batch_size': 10})
1118
1148
unbatched_view = create_initialized_view(
1119
bug.default_bugtask, '+index')
1121
len(unbatched_view.activity_and_comments),
1122
len(batched_view.activity_and_comments))
1123
for i in range(len(unbatched_view.activity_and_comments)):
1124
unbatched_item = unbatched_view.activity_and_comments[i]
1125
batched_item = batched_view.activity_and_comments[i]
1127
unbatched_item['comment'].text_for_display,
1128
batched_item['comment'].text_for_display)
1149
bug.default_bugtask, '+index', form={'comments': 'all'})
1150
# It may look slightly confusing, but it's because the unbatched
1151
# view's activity_and_comments list is indexed from comment 1,
1152
# whereas the batched view indexes from zero for ease-of-coding.
1153
# Comment 0 is the original bug description and so is rarely
1155
self._assertThatUnbatchedAndBatchedActivityMatch(
1156
unbatched_view.activity_and_comments[4:],
1157
batched_view.activity_and_comments)