OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """Unittests for monorail.tracker.issuedetail.""" |
| 7 |
| 8 import logging |
| 9 import mox |
| 10 import time |
| 11 import unittest |
| 12 |
| 13 import settings |
| 14 from features import notify |
| 15 from framework import permissions |
| 16 from framework import template_helpers |
| 17 from proto import project_pb2 |
| 18 from proto import tracker_pb2 |
| 19 from proto import user_pb2 |
| 20 from services import service_manager |
| 21 from services import issue_svc |
| 22 from testing import fake |
| 23 from testing import testing_helpers |
| 24 from tracker import issuedetail |
| 25 from tracker import tracker_constants |
| 26 from tracker import tracker_helpers |
| 27 |
| 28 |
| 29 class IssueDetailTest(unittest.TestCase): |
| 30 |
| 31 def setUp(self): |
| 32 self.cnxn = 'fake cnxn' |
| 33 self.services = service_manager.Services( |
| 34 config=fake.ConfigService(), |
| 35 issue=fake.IssueService(), |
| 36 user=fake.UserService(), |
| 37 project=fake.ProjectService(), |
| 38 issue_star=fake.IssueStarService(), |
| 39 spam=fake.SpamService()) |
| 40 self.project = self.services.project.TestAddProject('proj', project_id=987) |
| 41 self.config = tracker_pb2.ProjectIssueConfig() |
| 42 self.config.statuses_offer_merge.append('Duplicate') |
| 43 self.services.config.StoreConfig(self.cnxn, self.config) |
| 44 |
| 45 def testChooseNextPage(self): |
| 46 mr = testing_helpers.MakeMonorailRequest( |
| 47 path='/p/proj/issues/detail?id=123&q=term') |
| 48 mr.col_spec = '' |
| 49 config = tracker_pb2.ProjectIssueConfig() |
| 50 issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
| 51 |
| 52 url = issuedetail._ChooseNextPage( |
| 53 mr, issue.local_id, config, None, None, |
| 54 user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
| 55 self.assertTrue(url.startswith( |
| 56 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&q=term')) |
| 57 self.assertTrue(url.endswith('&updated=123')) |
| 58 |
| 59 url = issuedetail._ChooseNextPage( |
| 60 mr, issue.local_id, config, None, None, |
| 61 user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
| 62 self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=123&q=term', |
| 63 url) |
| 64 |
| 65 url = issuedetail._ChooseNextPage( |
| 66 mr, issue.local_id, config, None, None, |
| 67 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
| 68 self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
| 69 url) |
| 70 |
| 71 # If this is the last in the list, the next_id from the form will be ''. |
| 72 url = issuedetail._ChooseNextPage( |
| 73 mr, issue.local_id, config, None, None, |
| 74 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
| 75 self.assertTrue(url.startswith( |
| 76 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&q=term')) |
| 77 self.assertTrue(url.endswith('&updated=123')) |
| 78 |
| 79 def testChooseNextPage_ForMoveRequest(self): |
| 80 mr = testing_helpers.MakeMonorailRequest( |
| 81 path='/p/proj/issues/detail?id=123&q=term') |
| 82 mr.col_spec = '' |
| 83 config = tracker_pb2.ProjectIssueConfig() |
| 84 issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
| 85 moved_to_project_name = 'projB' |
| 86 moved_to_project_local_id = 543 |
| 87 moved_to_project_name_and_local_id = (moved_to_project_name, |
| 88 moved_to_project_local_id) |
| 89 |
| 90 url = issuedetail._ChooseNextPage( |
| 91 mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
| 92 user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
| 93 self.assertTrue(url.startswith( |
| 94 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&moved_to_id=' + |
| 95 str(moved_to_project_local_id) + '&moved_to_project=' + |
| 96 moved_to_project_name + '&q=term')) |
| 97 |
| 98 url = issuedetail._ChooseNextPage( |
| 99 mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
| 100 user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
| 101 self.assertEqual( |
| 102 'http://127.0.0.1/p/%s/issues/detail?id=123&q=term' % ( |
| 103 moved_to_project_name), |
| 104 url) |
| 105 mr.project_name = 'proj' # reset project name back. |
| 106 |
| 107 url = issuedetail._ChooseNextPage( |
| 108 mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
| 109 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
| 110 self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
| 111 url) |
| 112 |
| 113 # If this is the last in the list, the next_id from the form will be ''. |
| 114 url = issuedetail._ChooseNextPage( |
| 115 mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
| 116 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
| 117 self.assertTrue(url.startswith( |
| 118 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&moved_to_id=' + |
| 119 str(moved_to_project_local_id) + '&moved_to_project=' + |
| 120 moved_to_project_name + '&q=term')) |
| 121 |
| 122 def testChooseNextPage_ForCopyRequest(self): |
| 123 mr = testing_helpers.MakeMonorailRequest( |
| 124 path='/p/proj/issues/detail?id=123&q=term') |
| 125 mr.col_spec = '' |
| 126 config = tracker_pb2.ProjectIssueConfig() |
| 127 issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
| 128 copied_to_project_name = 'projB' |
| 129 copied_to_project_local_id = 543 |
| 130 copied_to_project_name_and_local_id = (copied_to_project_name, |
| 131 copied_to_project_local_id) |
| 132 |
| 133 url = issuedetail._ChooseNextPage( |
| 134 mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
| 135 user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
| 136 self.assertTrue(url.startswith( |
| 137 'http://127.0.0.1/p/proj/issues/list?copied_from_id=123' |
| 138 '&copied_to_id=' + str(copied_to_project_local_id) + |
| 139 '&copied_to_project=' + copied_to_project_name + |
| 140 '&cursor=proj%3A123&q=term')) |
| 141 |
| 142 url = issuedetail._ChooseNextPage( |
| 143 mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
| 144 user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
| 145 self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=123&q=term', url) |
| 146 mr.project_name = 'proj' # reset project name back. |
| 147 |
| 148 url = issuedetail._ChooseNextPage( |
| 149 mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
| 150 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
| 151 self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
| 152 url) |
| 153 |
| 154 # If this is the last in the list, the next_id from the form will be ''. |
| 155 url = issuedetail._ChooseNextPage( |
| 156 mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
| 157 user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
| 158 self.assertTrue(url.startswith( |
| 159 'http://127.0.0.1/p/proj/issues/list?copied_from_id=123' |
| 160 '&copied_to_id=' + str(copied_to_project_local_id) + |
| 161 '&copied_to_project=' + copied_to_project_name + |
| 162 '&cursor=proj%3A123&q=term')) |
| 163 |
| 164 def testGatherHelpData(self): |
| 165 servlet = issuedetail.IssueDetail('req', 'res', services=self.services) |
| 166 mr = testing_helpers.MakeMonorailRequest() |
| 167 |
| 168 # User did not jump to an issue, no query at all. |
| 169 help_data = servlet.GatherHelpData(mr, {}) |
| 170 self.assertEqual(None, help_data['cue']) |
| 171 |
| 172 # User did not jump to an issue, query was not a local ID number. |
| 173 mr.query = 'memory leak' |
| 174 help_data = servlet.GatherHelpData(mr, {}) |
| 175 self.assertEqual(None, help_data['cue']) |
| 176 |
| 177 # User jumped directly to an issue, maybe they meant to search instead. |
| 178 mr.query = '123' |
| 179 help_data = servlet.GatherHelpData(mr, {}) |
| 180 self.assertEqual('search_for_numbers', help_data['cue']) |
| 181 self.assertEqual(123, help_data['jump_local_id']) |
| 182 |
| 183 |
| 184 class IssueDetailFunctionsTest(unittest.TestCase): |
| 185 |
| 186 def setUp(self): |
| 187 self.project_name = 'proj' |
| 188 self.project_id = 987 |
| 189 self.cnxn = 'fake cnxn' |
| 190 self.services = service_manager.Services( |
| 191 config=fake.ConfigService(), |
| 192 issue=fake.IssueService(), |
| 193 issue_star=fake.IssueStarService(), |
| 194 project=fake.ProjectService(), |
| 195 user=fake.UserService()) |
| 196 self.project = self.services.project.TestAddProject( |
| 197 'proj', project_id=987, committer_ids=[111L]) |
| 198 self.servlet = issuedetail.IssueDetail( |
| 199 'req', 'res', services=self.services) |
| 200 self.mox = mox.Mox() |
| 201 |
| 202 def tearDown(self): |
| 203 self.mox.UnsetStubs() |
| 204 self.mox.ResetAll() |
| 205 |
| 206 def VerifyShouldShowFlipper( |
| 207 self, expected, query, sort_spec, can, create_issues=0): |
| 208 """Instantiate a _Flipper and check if makes a pipeline or not.""" |
| 209 services = service_manager.Services( |
| 210 config=fake.ConfigService(), |
| 211 issue=fake.IssueService(), |
| 212 project=fake.ProjectService(), |
| 213 user=fake.UserService()) |
| 214 mr = testing_helpers.MakeMonorailRequest(project=self.project) |
| 215 mr.query = query |
| 216 mr.sort_spec = sort_spec |
| 217 mr.can = can |
| 218 mr.project_name = self.project.project_name |
| 219 mr.project = self.project |
| 220 |
| 221 for idx in range(create_issues): |
| 222 _local_id = services.issue.CreateIssue( |
| 223 self.cnxn, services, self.project.project_id, |
| 224 'summary_%d' % idx, 'status', 111L, [], [], [], [], 111L, |
| 225 'description_%d' % idx) |
| 226 |
| 227 self.assertEqual( |
| 228 expected, |
| 229 issuedetail._ShouldShowFlipper(mr, services)) |
| 230 |
| 231 def testShouldShowFlipper_RegularSizedProject(self): |
| 232 # If the user is looking for a specific issue, no flipper. |
| 233 self.VerifyShouldShowFlipper( |
| 234 False, '123', '', tracker_constants.OPEN_ISSUES_CAN) |
| 235 self.VerifyShouldShowFlipper(False, '123', '', 5) |
| 236 self.VerifyShouldShowFlipper( |
| 237 False, '123', 'priority', tracker_constants.OPEN_ISSUES_CAN) |
| 238 |
| 239 # If the user did a search or sort or all in a small can, show flipper. |
| 240 self.VerifyShouldShowFlipper( |
| 241 True, 'memory leak', '', tracker_constants.OPEN_ISSUES_CAN) |
| 242 self.VerifyShouldShowFlipper( |
| 243 True, 'id=1,2,3', '', tracker_constants.OPEN_ISSUES_CAN) |
| 244 # Any can other than 1 or 2 is doing a query and so it should have a |
| 245 # failry narrow result set size. 5 is issues starred by me. |
| 246 self.VerifyShouldShowFlipper(True, '', '', 5) |
| 247 self.VerifyShouldShowFlipper( |
| 248 True, '', 'status', tracker_constants.OPEN_ISSUES_CAN) |
| 249 |
| 250 # In a project without a huge number of issues, still show the flipper even |
| 251 # if there was no specific query. |
| 252 self.VerifyShouldShowFlipper( |
| 253 True, '', '', tracker_constants.OPEN_ISSUES_CAN) |
| 254 |
| 255 def testShouldShowFlipper_LargeSizedProject(self): |
| 256 settings.threshold_to_suppress_prev_next = 1 |
| 257 |
| 258 # In a project that has tons of issues, save time by not showing the |
| 259 # flipper unless there was a specific query, sort, or can. |
| 260 self.VerifyShouldShowFlipper( |
| 261 False, '', '', tracker_constants.ALL_ISSUES_CAN, create_issues=3) |
| 262 self.VerifyShouldShowFlipper( |
| 263 False, '', '', tracker_constants.OPEN_ISSUES_CAN, create_issues=3) |
| 264 |
| 265 def testFieldEditPermitted_NoEdit(self): |
| 266 page_perms = testing_helpers.Blank( |
| 267 EditIssueSummary=False, EditIssueStatus=False, EditIssueOwner=False, |
| 268 EditIssueCc=False) # no perms are needed. |
| 269 self.assertTrue(issuedetail._FieldEditPermitted( |
| 270 [], '', '', '', '', 0, [], page_perms)) |
| 271 |
| 272 def testFieldEditPermitted_AllNeededPerms(self): |
| 273 page_perms = testing_helpers.Blank( |
| 274 EditIssueSummary=True, EditIssueStatus=True, EditIssueOwner=True, |
| 275 EditIssueCc=True) |
| 276 self.assertTrue(issuedetail._FieldEditPermitted( |
| 277 [], '', '', 'new sum', 'new status', 111L, [222L], page_perms)) |
| 278 |
| 279 def testFieldEditPermitted_MissingPerms(self): |
| 280 page_perms = testing_helpers.Blank( |
| 281 EditIssueSummary=False, EditIssueStatus=False, EditIssueOwner=False, |
| 282 EditIssueCc=False) # no perms. |
| 283 self.assertFalse(issuedetail._FieldEditPermitted( |
| 284 [], '', '', 'new sum', '', 0, [], page_perms)) |
| 285 self.assertFalse(issuedetail._FieldEditPermitted( |
| 286 [], '', '', '', 'new status', 0, [], page_perms)) |
| 287 self.assertFalse(issuedetail._FieldEditPermitted( |
| 288 [], '', '', '', '', 111L, [], page_perms)) |
| 289 self.assertFalse(issuedetail._FieldEditPermitted( |
| 290 [], '', '', '', '', 0, [222L], page_perms)) |
| 291 |
| 292 def testFieldEditPermitted_NeededPermsNotOffered(self): |
| 293 """Even if user has all the field-level perms, they still can't do this.""" |
| 294 page_perms = testing_helpers.Blank( |
| 295 EditIssueSummary=True, EditIssueStatus=True, EditIssueOwner=True, |
| 296 EditIssueCc=True) |
| 297 self.assertFalse(issuedetail._FieldEditPermitted( |
| 298 ['NewLabel'], '', '', '', '', 0, [], page_perms)) |
| 299 self.assertFalse(issuedetail._FieldEditPermitted( |
| 300 [], 'new blocked on', '', '', '', 0, [], page_perms)) |
| 301 self.assertFalse(issuedetail._FieldEditPermitted( |
| 302 [], '', 'new blocking', '', '', 0, [], page_perms)) |
| 303 |
| 304 def testValidateOwner_ChangedToValidOwner(self): |
| 305 post_data_owner = 'superman@krypton.com' |
| 306 parsed_owner_id = 111 |
| 307 original_issue_owner_id = 111 |
| 308 mr = testing_helpers.MakeMonorailRequest(project=self.project) |
| 309 |
| 310 self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
| 311 tracker_helpers.IsValidIssueOwner( |
| 312 mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
| 313 (True, '')) |
| 314 self.mox.ReplayAll() |
| 315 |
| 316 ret = self.servlet._ValidateOwner( |
| 317 mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
| 318 self.mox.VerifyAll() |
| 319 self.assertIsNone(ret) |
| 320 |
| 321 def testValidateOwner_UnchangedInvalidOwner(self): |
| 322 post_data_owner = 'superman@krypton.com' |
| 323 parsed_owner_id = 111 |
| 324 original_issue_owner_id = 111 |
| 325 mr = testing_helpers.MakeMonorailRequest(project=self.project) |
| 326 self.services.user.TestAddUser(post_data_owner, original_issue_owner_id) |
| 327 |
| 328 self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
| 329 tracker_helpers.IsValidIssueOwner( |
| 330 mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
| 331 (False, 'invalid owner')) |
| 332 self.mox.ReplayAll() |
| 333 |
| 334 ret = self.servlet._ValidateOwner( |
| 335 mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
| 336 self.mox.VerifyAll() |
| 337 self.assertIsNone(ret) |
| 338 |
| 339 def testValidateOwner_ChangedFromValidToInvalidOwner(self): |
| 340 post_data_owner = 'lexluthor' |
| 341 parsed_owner_id = 111 |
| 342 original_issue_owner_id = 111 |
| 343 original_issue_owner = 'superman@krypton.com' |
| 344 mr = testing_helpers.MakeMonorailRequest(project=self.project) |
| 345 self.services.user.TestAddUser(original_issue_owner, |
| 346 original_issue_owner_id) |
| 347 |
| 348 self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
| 349 tracker_helpers.IsValidIssueOwner( |
| 350 mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
| 351 (False, 'invalid owner')) |
| 352 self.mox.ReplayAll() |
| 353 |
| 354 ret = self.servlet._ValidateOwner( |
| 355 mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
| 356 self.mox.VerifyAll() |
| 357 self.assertEquals('invalid owner', ret) |
| 358 |
| 359 def testProcessFormData_NoPermission(self): |
| 360 """Anonymous users and users without ADD_ISSUE_COMMENT cannot comment.""" |
| 361 local_id_1 = self.services.issue.CreateIssue( |
| 362 self.cnxn, self.services, self.project.project_id, |
| 363 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
| 364 _, mr = testing_helpers.GetRequestObjects( |
| 365 project=self.project, |
| 366 perms=permissions.CONTRIBUTOR_INACTIVE_PERMISSIONSET) |
| 367 mr.auth.user_id = 0 |
| 368 mr.local_id = local_id_1 |
| 369 self.assertRaises(permissions.PermissionException, |
| 370 self.servlet.ProcessFormData, mr, {}) |
| 371 mr.auth.user_id = 111L |
| 372 self.assertRaises(permissions.PermissionException, |
| 373 self.servlet.ProcessFormData, mr, {}) |
| 374 |
| 375 def testProcessFormData_NonMembersCantEdit(self): |
| 376 """Non-members can comment, but never affect issue fields.""" |
| 377 orig_prepsend = notify.PrepareAndSendIssueChangeNotification |
| 378 notify.PrepareAndSendIssueChangeNotification = lambda *args, **kwargs: None |
| 379 |
| 380 local_id_1 = self.services.issue.CreateIssue( |
| 381 self.cnxn, self.services, self.project.project_id, |
| 382 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
| 383 local_id_2 = self.services.issue.CreateIssue( |
| 384 self.cnxn, self.services, self.project.project_id, |
| 385 'summary_2', 'status', 111L, [], [], [], [], 111L, 'description_2') |
| 386 |
| 387 _amendments, _cmnt_pb = self.services.issue.ApplyIssueComment( |
| 388 self.cnxn, self.services, 111L, |
| 389 self.project.project_id, local_id_2, 'summary', 'Duplicate', 111L, |
| 390 [], [], [], [], [], [], [], [], local_id_1, |
| 391 comment='closing as a dup of 1') |
| 392 |
| 393 non_member_user_id = 999L |
| 394 post_data = fake.PostData({ |
| 395 'merge_into': [''], # non-member tries to remove merged_into |
| 396 'comment': ['thanks!'], |
| 397 'can': ['1'], |
| 398 'q': ['foo'], |
| 399 'colspec': ['bar'], |
| 400 'sort': 'baz', |
| 401 'groupby': 'qux', |
| 402 'start': ['0'], |
| 403 'num': ['100'], |
| 404 'pagegen': [str(int(time.time()) + 1)], |
| 405 }) |
| 406 |
| 407 _, mr = testing_helpers.GetRequestObjects( |
| 408 user_info={'user_id': non_member_user_id}, |
| 409 path='/p/proj/issues/detail.do?id=%d' % local_id_2, |
| 410 project=self.project, method='POST', |
| 411 perms=permissions.USER_PERMISSIONSET) |
| 412 mr.project_name = self.project.project_name |
| 413 mr.project = self.project |
| 414 |
| 415 # The form should be processed and redirect back to viewing the issue. |
| 416 redirect_url = self.servlet.ProcessFormData(mr, post_data) |
| 417 self.assertTrue(redirect_url.startswith( |
| 418 'http://127.0.0.1/p/proj/issues/detail?id=%d' % local_id_2)) |
| 419 |
| 420 # BUT, issue should not have been edited because user lacked permission. |
| 421 updated_issue_2 = self.services.issue.GetIssueByLocalID( |
| 422 self.cnxn, self.project.project_id, local_id_2) |
| 423 self.assertEqual(local_id_1, updated_issue_2.merged_into) |
| 424 |
| 425 notify.PrepareAndSendIssueChangeNotification = orig_prepsend |
| 426 |
| 427 def testProcessFormData_DuplicateAddsACommentToTarget(self): |
| 428 """Marking issue 2 as dup of 1 adds a comment to 1.""" |
| 429 orig_prepsend = notify.PrepareAndSendIssueChangeNotification |
| 430 notify.PrepareAndSendIssueChangeNotification = lambda *args, **kwargs: None |
| 431 orig_get_starrers = tracker_helpers.GetNewIssueStarrers |
| 432 tracker_helpers.GetNewIssueStarrers = lambda *args, **kwargs: [] |
| 433 |
| 434 local_id_1 = self.services.issue.CreateIssue( |
| 435 self.cnxn, self.services, self.project.project_id, |
| 436 'summary_1', 'New', 111L, [], [], [], [], 111L, 'description_1') |
| 437 issue_1 = self.services.issue.GetIssueByLocalID( |
| 438 self.cnxn, self.project.project_id, local_id_1) |
| 439 issue_1.project_name = 'proj' |
| 440 local_id_2 = self.services.issue.CreateIssue( |
| 441 self.cnxn, self.services, self.project.project_id, |
| 442 'summary_2', 'New', 111L, [], [], [], [], 111L, 'description_2') |
| 443 issue_2 = self.services.issue.GetIssueByLocalID( |
| 444 self.cnxn, self.project.project_id, local_id_2) |
| 445 issue_2.project_name = 'proj' |
| 446 |
| 447 post_data = fake.PostData({ |
| 448 'status': ['Duplicate'], |
| 449 'merge_into': [str(local_id_1)], |
| 450 'comment': ['marking as dup'], |
| 451 'can': ['1'], |
| 452 'q': ['foo'], |
| 453 'colspec': ['bar'], |
| 454 'sort': 'baz', |
| 455 'groupby': 'qux', |
| 456 'start': ['0'], |
| 457 'num': ['100'], |
| 458 'pagegen': [str(int(time.time()) + 1)], |
| 459 }) |
| 460 |
| 461 member_user_id = 111L |
| 462 _, mr = testing_helpers.GetRequestObjects( |
| 463 user_info={'user_id': member_user_id}, |
| 464 path='/p/proj/issues/detail.do?id=%d' % local_id_2, |
| 465 project=self.project, method='POST', |
| 466 perms=permissions.COMMITTER_ACTIVE_PERMISSIONSET) |
| 467 mr.project_name = self.project.project_name |
| 468 mr.project = self.project |
| 469 |
| 470 # The form should be processed and redirect back to viewing the issue. |
| 471 self.servlet.ProcessFormData(mr, post_data) |
| 472 |
| 473 self.assertEqual('Duplicate', issue_2.status) |
| 474 self.assertEqual(issue_1.issue_id, issue_2.merged_into) |
| 475 comments_1 = self.services.issue.GetCommentsForIssue( |
| 476 self.cnxn, issue_1.issue_id) |
| 477 self.assertEqual(2, len(comments_1)) |
| 478 self.assertEqual( |
| 479 'Issue 2 has been merged into this issue.', |
| 480 comments_1[1].content) |
| 481 |
| 482 # Making another comment on issue 2 does not affect issue 1. |
| 483 self.servlet.ProcessFormData(mr, post_data) |
| 484 comments_1 = self.services.issue.GetCommentsForIssue( |
| 485 self.cnxn, issue_1.issue_id) |
| 486 self.assertEqual(2, len(comments_1)) |
| 487 |
| 488 notify.PrepareAndSendIssueChangeNotification = orig_prepsend |
| 489 tracker_helpers.GetNewIssueStarrers = orig_get_starrers |
| 490 |
| 491 # TODO(jrobbins): add more unit tests for other aspects of ProcessForm. |
| 492 |
| 493 |
| 494 class SetStarFormTest(unittest.TestCase): |
| 495 |
| 496 def setUp(self): |
| 497 self.cnxn = 'fake cnxn' |
| 498 self.services = service_manager.Services( |
| 499 config=fake.ConfigService(), |
| 500 issue=fake.IssueService(), |
| 501 user=fake.UserService(), |
| 502 project=fake.ProjectService(), |
| 503 issue_star=fake.IssueStarService()) |
| 504 self.project = self.services.project.TestAddProject('proj', project_id=987) |
| 505 self.servlet = issuedetail.SetStarForm( |
| 506 'req', 'res', services=self.services) |
| 507 |
| 508 def testAssertBasePermission(self): |
| 509 """Only users with SET_STAR could set star.""" |
| 510 local_id_1 = self.services.issue.CreateIssue( |
| 511 self.cnxn, self.services, self.project.project_id, |
| 512 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
| 513 _, mr = testing_helpers.GetRequestObjects( |
| 514 project=self.project, |
| 515 perms=permissions.READ_ONLY_PERMISSIONSET) |
| 516 mr.local_id = local_id_1 |
| 517 self.assertRaises(permissions.PermissionException, |
| 518 self.servlet.AssertBasePermission, mr) |
| 519 _, mr = testing_helpers.GetRequestObjects( |
| 520 project=self.project, |
| 521 perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET) |
| 522 mr.local_id = local_id_1 |
| 523 self.servlet.AssertBasePermission(mr) |
| 524 |
| 525 |
| 526 class IssueCommentDeletionTest(unittest.TestCase): |
| 527 |
| 528 def setUp(self): |
| 529 self.cnxn = 'fake cnxn' |
| 530 self.services = service_manager.Services( |
| 531 config=fake.ConfigService(), |
| 532 issue=fake.IssueService(), |
| 533 user=fake.UserService(), |
| 534 project=fake.ProjectService(), |
| 535 issue_star=fake.IssueStarService()) |
| 536 self.project = self.services.project.TestAddProject('proj', project_id=987) |
| 537 self.servlet = issuedetail.IssueCommentDeletion( |
| 538 'req', 'res', services=self.services) |
| 539 |
| 540 def testProcessFormData_Permission(self): |
| 541 """Permit users who can delete.""" |
| 542 local_id_1 = self.services.issue.CreateIssue( |
| 543 self.cnxn, self.services, self.project.project_id, |
| 544 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
| 545 _, mr = testing_helpers.GetRequestObjects( |
| 546 project=self.project, |
| 547 perms=permissions.READ_ONLY_PERMISSIONSET) |
| 548 mr.local_id = local_id_1 |
| 549 mr.auth.user_id = 222L |
| 550 post_data = { |
| 551 'id': local_id_1, |
| 552 'sequence_num': 0, |
| 553 'mode': 0} |
| 554 self.assertRaises(permissions.PermissionException, |
| 555 self.servlet.ProcessFormData, mr, post_data) |
| 556 _, mr = testing_helpers.GetRequestObjects( |
| 557 project=self.project, |
| 558 perms=permissions.OWNER_ACTIVE_PERMISSIONSET) |
| 559 mr.local_id = local_id_1 |
| 560 mr.auth.user_id = 222L |
| 561 self.servlet.ProcessFormData(mr, post_data) |
| 562 |
| 563 |
| 564 if __name__ == '__main__': |
| 565 unittest.main() |
OLD | NEW |