blob: fe51ddf68557f030c83cf3bec304fecefd81d099 [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2016 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""Unittests for monorail.tracker.issuedetailezt."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import logging
11import mock
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +020012try:
13 from mox3 import mox
14except ImportError:
15 import mox
Copybara854996b2021-09-07 19:36:02 +000016import time
17import unittest
18
19import settings
20from businesslogic import work_env
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010021from mrproto import features_pb2
Copybara854996b2021-09-07 19:36:02 +000022from features import hotlist_views
23from features import send_notifications
24from framework import authdata
25from framework import exceptions
26from framework import framework_views
27from framework import framework_helpers
28from framework import urls
29from framework import permissions
30from framework import profiler
31from framework import sorting
32from framework import template_helpers
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010033from mrproto import project_pb2
34from mrproto import tracker_pb2
35from mrproto import user_pb2
Copybara854996b2021-09-07 19:36:02 +000036from services import service_manager
37from services import issue_svc
38from services import tracker_fulltext
39from testing import fake
40from testing import testing_helpers
41from tracker import issuedetailezt
42from tracker import tracker_constants
43from tracker import tracker_helpers
44
45
46class GetAdjacentIssueTest(unittest.TestCase):
47
48 def setUp(self):
49 self.cnxn = 'fake cnxn'
50 self.services = service_manager.Services(
51 config=fake.ConfigService(),
52 issue=fake.IssueService(),
53 user=fake.UserService(),
54 project=fake.ProjectService(),
55 issue_star=fake.IssueStarService(),
56 spam=fake.SpamService())
57 self.services.project.TestAddProject('proj', project_id=789)
58 self.mr = testing_helpers.MakeMonorailRequest()
59 self.mr.auth.user_id = 111
60 self.mr.auth.effective_ids = {111}
61 self.mr.me_user_id = 111
62 self.work_env = work_env.WorkEnv(
63 self.mr, self.services, 'Testing phase')
64
65 def testGetAdjacentIssue_PrevIssue(self):
66 cur_issue = fake.MakeTestIssue(789, 2, 'sum', 'New', 111, issue_id=78902)
67 next_issue = fake.MakeTestIssue(789, 3, 'sum', 'New', 111, issue_id=78903)
68 prev_issue = fake.MakeTestIssue(789, 1, 'sum', 'New', 111, issue_id=78901)
69 self.services.issue.TestAddIssue(cur_issue)
70 self.services.issue.TestAddIssue(next_issue)
71 self.services.issue.TestAddIssue(prev_issue)
72
73 with self.work_env as we:
74 we.FindIssuePositionInSearch = mock.Mock(
75 return_value=[78901, 1, 78903, 3])
76
77 actual_issue = issuedetailezt.GetAdjacentIssue(
78 self.mr, we, cur_issue)
79 self.assertEqual(prev_issue, actual_issue)
80 we.FindIssuePositionInSearch.assert_called_once_with(cur_issue)
81
82 def testGetAdjacentIssue_NextIssue(self):
83 cur_issue = fake.MakeTestIssue(789, 2, 'sum', 'New', 111, issue_id=78902)
84 next_issue = fake.MakeTestIssue(789, 3, 'sum', 'New', 111, issue_id=78903)
85 prev_issue = fake.MakeTestIssue(789, 1, 'sum', 'New', 111, issue_id=78901)
86 self.services.issue.TestAddIssue(cur_issue)
87 self.services.issue.TestAddIssue(next_issue)
88 self.services.issue.TestAddIssue(prev_issue)
89
90 with self.work_env as we:
91 we.FindIssuePositionInSearch = mock.Mock(
92 return_value=[78901, 1, 78903, 3])
93
94 actual_issue = issuedetailezt.GetAdjacentIssue(
95 self.mr, we, cur_issue, next_issue=True)
96 self.assertEqual(next_issue, actual_issue)
97 we.FindIssuePositionInSearch.assert_called_once_with(cur_issue)
98
99 def testGetAdjacentIssue_NotFound(self):
100 cur_issue = fake.MakeTestIssue(789, 2, 'sum', 'New', 111, issue_id=78902)
101 prev_issue = fake.MakeTestIssue(789, 1, 'sum', 'New', 111, issue_id=78901)
102 self.services.issue.TestAddIssue(cur_issue)
103 self.services.issue.TestAddIssue(prev_issue)
104
105 with self.work_env as we:
106 we.FindIssuePositionInSearch = mock.Mock(
107 return_value=[78901, 1, 78903, 3])
108
109 with self.assertRaises(exceptions.NoSuchIssueException):
110 issuedetailezt.GetAdjacentIssue(
111 self.mr, we, cur_issue, next_issue=True)
112 we.FindIssuePositionInSearch.assert_called_once_with(cur_issue)
113
114 def testGetAdjacentIssue_Hotlist(self):
115 cur_issue = fake.MakeTestIssue(789, 2, 'sum', 'New', 111, issue_id=78902)
116 next_issue = fake.MakeTestIssue(789, 3, 'sum', 'New', 111, issue_id=78903)
117 prev_issue = fake.MakeTestIssue(789, 1, 'sum', 'New', 111, issue_id=78901)
118 self.services.issue.TestAddIssue(cur_issue)
119 self.services.issue.TestAddIssue(next_issue)
120 self.services.issue.TestAddIssue(prev_issue)
121 hotlist = fake.Hotlist('name', 678, owner_ids=[111])
122
123 with self.work_env as we:
124 we.GetIssuePositionInHotlist = mock.Mock(
125 return_value=[78901, 1, 78903, 3])
126
127 actual_issue = issuedetailezt.GetAdjacentIssue(
128 self.mr, we, cur_issue, hotlist=hotlist, next_issue=True)
129 self.assertEqual(next_issue, actual_issue)
130 we.GetIssuePositionInHotlist.assert_called_once_with(
131 cur_issue, hotlist, self.mr.can, self.mr.sort_spec,
132 self.mr.group_by_spec)
133
134
135class FlipperRedirectTest(unittest.TestCase):
136
137 def setUp(self):
138 self.services = service_manager.Services(
139 config=fake.ConfigService(),
140 features=fake.FeaturesService(),
141 issue=fake.IssueService(),
142 user=fake.UserService(),
143 project=fake.ProjectService())
144 self.project = self.services.project.TestAddProject(
145 'proj', project_id=987, committer_ids=[111])
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100146 self.next_servlet = issuedetailezt.FlipperNext(services=self.services)
147 self.prev_servlet = issuedetailezt.FlipperPrev(services=self.services)
148 self.list_servlet = issuedetailezt.FlipperList(services=self.services)
Copybara854996b2021-09-07 19:36:02 +0000149 mr = testing_helpers.MakeMonorailRequest(project=self.project)
150 mr.local_id = 123
151 mr.me_user_id = 111
152
153 self.next_servlet.mr = mr
154 self.prev_servlet.mr = mr
155 self.list_servlet.mr = mr
156
157 self.fake_issue_1 = fake.MakeTestIssue(987, 123, 'summary', 'New', 111,
158 project_name='rutabaga')
159 self.services.issue.TestAddIssue(self.fake_issue_1)
160 self.fake_issue_2 = fake.MakeTestIssue(987, 456, 'summary', 'New', 111,
161 project_name='rutabaga')
162 self.services.issue.TestAddIssue(self.fake_issue_2)
163 self.fake_issue_3 = fake.MakeTestIssue(987, 789, 'summary', 'New', 111,
164 project_name='potato')
165 self.services.issue.TestAddIssue(self.fake_issue_3)
166
167 self.next_servlet.redirect = mock.Mock()
168 self.prev_servlet.redirect = mock.Mock()
169 self.list_servlet.redirect = mock.Mock()
170
171 @mock.patch('tracker.issuedetailezt.GetAdjacentIssue')
172 def testFlipperNext(self, patchGetAdjacentIssue):
173 patchGetAdjacentIssue.return_value = self.fake_issue_2
174 self.next_servlet.mr.GetIntParam = mock.Mock(return_value=None)
175
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100176 self.next_servlet.get()
Copybara854996b2021-09-07 19:36:02 +0000177 self.next_servlet.mr.GetIntParam.assert_called_once_with('hotlist_id')
178 patchGetAdjacentIssue.assert_called_once()
179 self.next_servlet.redirect.assert_called_once_with(
180 '/p/rutabaga/issues/detail?id=456')
181
182 @mock.patch('tracker.issuedetailezt.GetAdjacentIssue')
183 def testFlipperNext_Hotlist(self, patchGetAdjacentIssue):
184 patchGetAdjacentIssue.return_value = self.fake_issue_3
185 self.next_servlet.mr.GetIntParam = mock.Mock(return_value=123)
186 # TODO(jeffcarp): Mock hotlist_id param on path here.
187
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100188 self.next_servlet.get()
Copybara854996b2021-09-07 19:36:02 +0000189 self.next_servlet.mr.GetIntParam.assert_called_with('hotlist_id')
190 self.next_servlet.redirect.assert_called_once_with(
191 '/p/potato/issues/detail?id=789')
192
193 @mock.patch('tracker.issuedetailezt.GetAdjacentIssue')
194 def testFlipperPrev(self, patchGetAdjacentIssue):
195 patchGetAdjacentIssue.return_value = self.fake_issue_2
196 self.next_servlet.mr.GetIntParam = mock.Mock(return_value=None)
197
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100198 self.prev_servlet.get()
Copybara854996b2021-09-07 19:36:02 +0000199 self.prev_servlet.mr.GetIntParam.assert_called_with('hotlist_id')
200 patchGetAdjacentIssue.assert_called_once()
201 self.prev_servlet.redirect.assert_called_once_with(
202 '/p/rutabaga/issues/detail?id=456')
203
204 @mock.patch('tracker.issuedetailezt.GetAdjacentIssue')
205 def testFlipperPrev_Hotlist(self, patchGetAdjacentIssue):
206 patchGetAdjacentIssue.return_value = self.fake_issue_3
207 self.prev_servlet.mr.GetIntParam = mock.Mock(return_value=123)
208 # TODO(jeffcarp): Mock hotlist_id param on path here.
209
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100210 self.prev_servlet.get()
Copybara854996b2021-09-07 19:36:02 +0000211 self.prev_servlet.mr.GetIntParam.assert_called_with('hotlist_id')
212 self.prev_servlet.redirect.assert_called_once_with(
213 '/p/potato/issues/detail?id=789')
214
215 @mock.patch('tracker.issuedetailezt._ComputeBackToListURL')
216 def testFlipperList(self, patch_ComputeBackToListURL):
217 patch_ComputeBackToListURL.return_value = '/p/test/issues/list'
218 self.list_servlet.mr.GetIntParam = mock.Mock(return_value=None)
219
220 self.list_servlet.get()
221
222 self.list_servlet.mr.GetIntParam.assert_called_with('hotlist_id')
223 patch_ComputeBackToListURL.assert_called_once()
224 self.list_servlet.redirect.assert_called_once_with(
225 '/p/test/issues/list')
226
227 @mock.patch('tracker.issuedetailezt._ComputeBackToListURL')
228 def testFlipperList_Hotlist(self, patch_ComputeBackToListURL):
229 patch_ComputeBackToListURL.return_value = '/p/test/issues/list'
230 self.list_servlet.mr.GetIntParam = mock.Mock(return_value=123)
231
232 self.list_servlet.get()
233
234 self.list_servlet.mr.GetIntParam.assert_called_with('hotlist_id')
235 self.list_servlet.redirect.assert_called_once_with(
236 '/p/test/issues/list')
237
238
239class ShouldShowFlipperTest(unittest.TestCase):
240
241 def setUp(self):
242 self.cnxn = 'fake cnxn'
243
244 def VerifyShouldShowFlipper(
245 self, expected, query, sort_spec, can, create_issues=0):
246 """Instantiate a _Flipper and check if makes a pipeline or not."""
247 services = service_manager.Services(
248 config=fake.ConfigService(),
249 issue=fake.IssueService(),
250 project=fake.ProjectService(),
251 user=fake.UserService())
252 project = services.project.TestAddProject(
253 'proj', project_id=987, committer_ids=[111])
254 mr = testing_helpers.MakeMonorailRequest(project=project)
255 mr.query = query
256 mr.sort_spec = sort_spec
257 mr.can = can
258 mr.project_name = project.project_name
259 mr.project = project
260
261 for idx in range(create_issues):
262 _created_issue = fake.MakeTestIssue(
263 project.project_id,
264 idx,
265 'summary_%d' % idx,
266 'status',
267 111,
268 reporter_id=111)
269 services.issue.TestAddIssue(_created_issue)
270
271 self.assertEqual(expected, issuedetailezt._ShouldShowFlipper(mr, services))
272
273 def testShouldShowFlipper_RegularSizedProject(self):
274 # If the user is looking for a specific issue, no flipper.
275 self.VerifyShouldShowFlipper(
276 False, '123', '', tracker_constants.OPEN_ISSUES_CAN)
277 self.VerifyShouldShowFlipper(False, '123', '', 5)
278 self.VerifyShouldShowFlipper(
279 False, '123', 'priority', tracker_constants.OPEN_ISSUES_CAN)
280
281 # If the user did a search or sort or all in a small can, show flipper.
282 self.VerifyShouldShowFlipper(
283 True, 'memory leak', '', tracker_constants.OPEN_ISSUES_CAN)
284 self.VerifyShouldShowFlipper(
285 True, 'id=1,2,3', '', tracker_constants.OPEN_ISSUES_CAN)
286 # Any can other than 1 or 2 is doing a query and so it should have a
287 # failry narrow result set size. 5 is issues starred by me.
288 self.VerifyShouldShowFlipper(True, '', '', 5)
289 self.VerifyShouldShowFlipper(
290 True, '', 'status', tracker_constants.OPEN_ISSUES_CAN)
291
292 # In a project without a huge number of issues, still show the flipper even
293 # if there was no specific query.
294 self.VerifyShouldShowFlipper(
295 True, '', '', tracker_constants.OPEN_ISSUES_CAN)
296
297 def testShouldShowFlipper_LargeSizedProject(self):
298 settings.threshold_to_suppress_prev_next = 1
299
300 # In a project that has tons of issues, save time by not showing the
301 # flipper unless there was a specific query, sort, or can.
302 self.VerifyShouldShowFlipper(
303 False, '', '', tracker_constants.ALL_ISSUES_CAN, create_issues=3)
304 self.VerifyShouldShowFlipper(
305 False, '', '', tracker_constants.OPEN_ISSUES_CAN, create_issues=3)