Index: appengine/monorail/tracker/test/issuedetail_test.py |
diff --git a/appengine/monorail/tracker/test/issuedetail_test.py b/appengine/monorail/tracker/test/issuedetail_test.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b001c7da465b873cd4998844fc6e186a239d61ab |
--- /dev/null |
+++ b/appengine/monorail/tracker/test/issuedetail_test.py |
@@ -0,0 +1,565 @@ |
+# Copyright 2016 The Chromium Authors. All rights reserved. |
+# Use of this source code is govered by a BSD-style |
+# license that can be found in the LICENSE file or at |
+# https://developers.google.com/open-source/licenses/bsd |
+ |
+"""Unittests for monorail.tracker.issuedetail.""" |
+ |
+import logging |
+import mox |
+import time |
+import unittest |
+ |
+import settings |
+from features import notify |
+from framework import permissions |
+from framework import template_helpers |
+from proto import project_pb2 |
+from proto import tracker_pb2 |
+from proto import user_pb2 |
+from services import service_manager |
+from services import issue_svc |
+from testing import fake |
+from testing import testing_helpers |
+from tracker import issuedetail |
+from tracker import tracker_constants |
+from tracker import tracker_helpers |
+ |
+ |
+class IssueDetailTest(unittest.TestCase): |
+ |
+ def setUp(self): |
+ self.cnxn = 'fake cnxn' |
+ self.services = service_manager.Services( |
+ config=fake.ConfigService(), |
+ issue=fake.IssueService(), |
+ user=fake.UserService(), |
+ project=fake.ProjectService(), |
+ issue_star=fake.IssueStarService(), |
+ spam=fake.SpamService()) |
+ self.project = self.services.project.TestAddProject('proj', project_id=987) |
+ self.config = tracker_pb2.ProjectIssueConfig() |
+ self.config.statuses_offer_merge.append('Duplicate') |
+ self.services.config.StoreConfig(self.cnxn, self.config) |
+ |
+ def testChooseNextPage(self): |
+ mr = testing_helpers.MakeMonorailRequest( |
+ path='/p/proj/issues/detail?id=123&q=term') |
+ mr.col_spec = '' |
+ config = tracker_pb2.ProjectIssueConfig() |
+ issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, None, |
+ user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&q=term')) |
+ self.assertTrue(url.endswith('&updated=123')) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, None, |
+ user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
+ self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=123&q=term', |
+ url) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, None, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
+ self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
+ url) |
+ |
+ # If this is the last in the list, the next_id from the form will be ''. |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, None, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&q=term')) |
+ self.assertTrue(url.endswith('&updated=123')) |
+ |
+ def testChooseNextPage_ForMoveRequest(self): |
+ mr = testing_helpers.MakeMonorailRequest( |
+ path='/p/proj/issues/detail?id=123&q=term') |
+ mr.col_spec = '' |
+ config = tracker_pb2.ProjectIssueConfig() |
+ issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
+ moved_to_project_name = 'projB' |
+ moved_to_project_local_id = 543 |
+ moved_to_project_name_and_local_id = (moved_to_project_name, |
+ moved_to_project_local_id) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
+ user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&moved_to_id=' + |
+ str(moved_to_project_local_id) + '&moved_to_project=' + |
+ moved_to_project_name + '&q=term')) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
+ user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
+ self.assertEqual( |
+ 'http://127.0.0.1/p/%s/issues/detail?id=123&q=term' % ( |
+ moved_to_project_name), |
+ url) |
+ mr.project_name = 'proj' # reset project name back. |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
+ self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
+ url) |
+ |
+ # If this is the last in the list, the next_id from the form will be ''. |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, moved_to_project_name_and_local_id, None, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?cursor=proj%3A123&moved_to_id=' + |
+ str(moved_to_project_local_id) + '&moved_to_project=' + |
+ moved_to_project_name + '&q=term')) |
+ |
+ def testChooseNextPage_ForCopyRequest(self): |
+ mr = testing_helpers.MakeMonorailRequest( |
+ path='/p/proj/issues/detail?id=123&q=term') |
+ mr.col_spec = '' |
+ config = tracker_pb2.ProjectIssueConfig() |
+ issue = fake.MakeTestIssue(987, 123, 'summary', 'New', 111L) |
+ copied_to_project_name = 'projB' |
+ copied_to_project_local_id = 543 |
+ copied_to_project_name_and_local_id = (copied_to_project_name, |
+ copied_to_project_local_id) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
+ user_pb2.IssueUpdateNav.UP_TO_LIST, '124') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?copied_from_id=123' |
+ '&copied_to_id=' + str(copied_to_project_local_id) + |
+ '&copied_to_project=' + copied_to_project_name + |
+ '&cursor=proj%3A123&q=term')) |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
+ user_pb2.IssueUpdateNav.STAY_SAME_ISSUE, '124') |
+ self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=123&q=term', url) |
+ mr.project_name = 'proj' # reset project name back. |
+ |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '124') |
+ self.assertEqual('http://127.0.0.1/p/proj/issues/detail?id=124&q=term', |
+ url) |
+ |
+ # If this is the last in the list, the next_id from the form will be ''. |
+ url = issuedetail._ChooseNextPage( |
+ mr, issue.local_id, config, None, copied_to_project_name_and_local_id, |
+ user_pb2.IssueUpdateNav.NEXT_IN_LIST, '') |
+ self.assertTrue(url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/list?copied_from_id=123' |
+ '&copied_to_id=' + str(copied_to_project_local_id) + |
+ '&copied_to_project=' + copied_to_project_name + |
+ '&cursor=proj%3A123&q=term')) |
+ |
+ def testGatherHelpData(self): |
+ servlet = issuedetail.IssueDetail('req', 'res', services=self.services) |
+ mr = testing_helpers.MakeMonorailRequest() |
+ |
+ # User did not jump to an issue, no query at all. |
+ help_data = servlet.GatherHelpData(mr, {}) |
+ self.assertEqual(None, help_data['cue']) |
+ |
+ # User did not jump to an issue, query was not a local ID number. |
+ mr.query = 'memory leak' |
+ help_data = servlet.GatherHelpData(mr, {}) |
+ self.assertEqual(None, help_data['cue']) |
+ |
+ # User jumped directly to an issue, maybe they meant to search instead. |
+ mr.query = '123' |
+ help_data = servlet.GatherHelpData(mr, {}) |
+ self.assertEqual('search_for_numbers', help_data['cue']) |
+ self.assertEqual(123, help_data['jump_local_id']) |
+ |
+ |
+class IssueDetailFunctionsTest(unittest.TestCase): |
+ |
+ def setUp(self): |
+ self.project_name = 'proj' |
+ self.project_id = 987 |
+ self.cnxn = 'fake cnxn' |
+ self.services = service_manager.Services( |
+ config=fake.ConfigService(), |
+ issue=fake.IssueService(), |
+ issue_star=fake.IssueStarService(), |
+ project=fake.ProjectService(), |
+ user=fake.UserService()) |
+ self.project = self.services.project.TestAddProject( |
+ 'proj', project_id=987, committer_ids=[111L]) |
+ self.servlet = issuedetail.IssueDetail( |
+ 'req', 'res', services=self.services) |
+ self.mox = mox.Mox() |
+ |
+ def tearDown(self): |
+ self.mox.UnsetStubs() |
+ self.mox.ResetAll() |
+ |
+ def VerifyShouldShowFlipper( |
+ self, expected, query, sort_spec, can, create_issues=0): |
+ """Instantiate a _Flipper and check if makes a pipeline or not.""" |
+ services = service_manager.Services( |
+ config=fake.ConfigService(), |
+ issue=fake.IssueService(), |
+ project=fake.ProjectService(), |
+ user=fake.UserService()) |
+ mr = testing_helpers.MakeMonorailRequest(project=self.project) |
+ mr.query = query |
+ mr.sort_spec = sort_spec |
+ mr.can = can |
+ mr.project_name = self.project.project_name |
+ mr.project = self.project |
+ |
+ for idx in range(create_issues): |
+ _local_id = services.issue.CreateIssue( |
+ self.cnxn, services, self.project.project_id, |
+ 'summary_%d' % idx, 'status', 111L, [], [], [], [], 111L, |
+ 'description_%d' % idx) |
+ |
+ self.assertEqual( |
+ expected, |
+ issuedetail._ShouldShowFlipper(mr, services)) |
+ |
+ def testShouldShowFlipper_RegularSizedProject(self): |
+ # If the user is looking for a specific issue, no flipper. |
+ self.VerifyShouldShowFlipper( |
+ False, '123', '', tracker_constants.OPEN_ISSUES_CAN) |
+ self.VerifyShouldShowFlipper(False, '123', '', 5) |
+ self.VerifyShouldShowFlipper( |
+ False, '123', 'priority', tracker_constants.OPEN_ISSUES_CAN) |
+ |
+ # If the user did a search or sort or all in a small can, show flipper. |
+ self.VerifyShouldShowFlipper( |
+ True, 'memory leak', '', tracker_constants.OPEN_ISSUES_CAN) |
+ self.VerifyShouldShowFlipper( |
+ True, 'id=1,2,3', '', tracker_constants.OPEN_ISSUES_CAN) |
+ # Any can other than 1 or 2 is doing a query and so it should have a |
+ # failry narrow result set size. 5 is issues starred by me. |
+ self.VerifyShouldShowFlipper(True, '', '', 5) |
+ self.VerifyShouldShowFlipper( |
+ True, '', 'status', tracker_constants.OPEN_ISSUES_CAN) |
+ |
+ # In a project without a huge number of issues, still show the flipper even |
+ # if there was no specific query. |
+ self.VerifyShouldShowFlipper( |
+ True, '', '', tracker_constants.OPEN_ISSUES_CAN) |
+ |
+ def testShouldShowFlipper_LargeSizedProject(self): |
+ settings.threshold_to_suppress_prev_next = 1 |
+ |
+ # In a project that has tons of issues, save time by not showing the |
+ # flipper unless there was a specific query, sort, or can. |
+ self.VerifyShouldShowFlipper( |
+ False, '', '', tracker_constants.ALL_ISSUES_CAN, create_issues=3) |
+ self.VerifyShouldShowFlipper( |
+ False, '', '', tracker_constants.OPEN_ISSUES_CAN, create_issues=3) |
+ |
+ def testFieldEditPermitted_NoEdit(self): |
+ page_perms = testing_helpers.Blank( |
+ EditIssueSummary=False, EditIssueStatus=False, EditIssueOwner=False, |
+ EditIssueCc=False) # no perms are needed. |
+ self.assertTrue(issuedetail._FieldEditPermitted( |
+ [], '', '', '', '', 0, [], page_perms)) |
+ |
+ def testFieldEditPermitted_AllNeededPerms(self): |
+ page_perms = testing_helpers.Blank( |
+ EditIssueSummary=True, EditIssueStatus=True, EditIssueOwner=True, |
+ EditIssueCc=True) |
+ self.assertTrue(issuedetail._FieldEditPermitted( |
+ [], '', '', 'new sum', 'new status', 111L, [222L], page_perms)) |
+ |
+ def testFieldEditPermitted_MissingPerms(self): |
+ page_perms = testing_helpers.Blank( |
+ EditIssueSummary=False, EditIssueStatus=False, EditIssueOwner=False, |
+ EditIssueCc=False) # no perms. |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], '', '', 'new sum', '', 0, [], page_perms)) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], '', '', '', 'new status', 0, [], page_perms)) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], '', '', '', '', 111L, [], page_perms)) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], '', '', '', '', 0, [222L], page_perms)) |
+ |
+ def testFieldEditPermitted_NeededPermsNotOffered(self): |
+ """Even if user has all the field-level perms, they still can't do this.""" |
+ page_perms = testing_helpers.Blank( |
+ EditIssueSummary=True, EditIssueStatus=True, EditIssueOwner=True, |
+ EditIssueCc=True) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ ['NewLabel'], '', '', '', '', 0, [], page_perms)) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], 'new blocked on', '', '', '', 0, [], page_perms)) |
+ self.assertFalse(issuedetail._FieldEditPermitted( |
+ [], '', 'new blocking', '', '', 0, [], page_perms)) |
+ |
+ def testValidateOwner_ChangedToValidOwner(self): |
+ post_data_owner = 'superman@krypton.com' |
+ parsed_owner_id = 111 |
+ original_issue_owner_id = 111 |
+ mr = testing_helpers.MakeMonorailRequest(project=self.project) |
+ |
+ self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
+ tracker_helpers.IsValidIssueOwner( |
+ mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
+ (True, '')) |
+ self.mox.ReplayAll() |
+ |
+ ret = self.servlet._ValidateOwner( |
+ mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
+ self.mox.VerifyAll() |
+ self.assertIsNone(ret) |
+ |
+ def testValidateOwner_UnchangedInvalidOwner(self): |
+ post_data_owner = 'superman@krypton.com' |
+ parsed_owner_id = 111 |
+ original_issue_owner_id = 111 |
+ mr = testing_helpers.MakeMonorailRequest(project=self.project) |
+ self.services.user.TestAddUser(post_data_owner, original_issue_owner_id) |
+ |
+ self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
+ tracker_helpers.IsValidIssueOwner( |
+ mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
+ (False, 'invalid owner')) |
+ self.mox.ReplayAll() |
+ |
+ ret = self.servlet._ValidateOwner( |
+ mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
+ self.mox.VerifyAll() |
+ self.assertIsNone(ret) |
+ |
+ def testValidateOwner_ChangedFromValidToInvalidOwner(self): |
+ post_data_owner = 'lexluthor' |
+ parsed_owner_id = 111 |
+ original_issue_owner_id = 111 |
+ original_issue_owner = 'superman@krypton.com' |
+ mr = testing_helpers.MakeMonorailRequest(project=self.project) |
+ self.services.user.TestAddUser(original_issue_owner, |
+ original_issue_owner_id) |
+ |
+ self.mox.StubOutWithMock(tracker_helpers, 'IsValidIssueOwner') |
+ tracker_helpers.IsValidIssueOwner( |
+ mr.cnxn, mr.project, parsed_owner_id, self.services).AndReturn( |
+ (False, 'invalid owner')) |
+ self.mox.ReplayAll() |
+ |
+ ret = self.servlet._ValidateOwner( |
+ mr, post_data_owner, parsed_owner_id, original_issue_owner_id) |
+ self.mox.VerifyAll() |
+ self.assertEquals('invalid owner', ret) |
+ |
+ def testProcessFormData_NoPermission(self): |
+ """Anonymous users and users without ADD_ISSUE_COMMENT cannot comment.""" |
+ local_id_1 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
+ _, mr = testing_helpers.GetRequestObjects( |
+ project=self.project, |
+ perms=permissions.CONTRIBUTOR_INACTIVE_PERMISSIONSET) |
+ mr.auth.user_id = 0 |
+ mr.local_id = local_id_1 |
+ self.assertRaises(permissions.PermissionException, |
+ self.servlet.ProcessFormData, mr, {}) |
+ mr.auth.user_id = 111L |
+ self.assertRaises(permissions.PermissionException, |
+ self.servlet.ProcessFormData, mr, {}) |
+ |
+ def testProcessFormData_NonMembersCantEdit(self): |
+ """Non-members can comment, but never affect issue fields.""" |
+ orig_prepsend = notify.PrepareAndSendIssueChangeNotification |
+ notify.PrepareAndSendIssueChangeNotification = lambda *args, **kwargs: None |
+ |
+ local_id_1 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
+ local_id_2 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_2', 'status', 111L, [], [], [], [], 111L, 'description_2') |
+ |
+ _amendments, _cmnt_pb = self.services.issue.ApplyIssueComment( |
+ self.cnxn, self.services, 111L, |
+ self.project.project_id, local_id_2, 'summary', 'Duplicate', 111L, |
+ [], [], [], [], [], [], [], [], local_id_1, |
+ comment='closing as a dup of 1') |
+ |
+ non_member_user_id = 999L |
+ post_data = fake.PostData({ |
+ 'merge_into': [''], # non-member tries to remove merged_into |
+ 'comment': ['thanks!'], |
+ 'can': ['1'], |
+ 'q': ['foo'], |
+ 'colspec': ['bar'], |
+ 'sort': 'baz', |
+ 'groupby': 'qux', |
+ 'start': ['0'], |
+ 'num': ['100'], |
+ 'pagegen': [str(int(time.time()) + 1)], |
+ }) |
+ |
+ _, mr = testing_helpers.GetRequestObjects( |
+ user_info={'user_id': non_member_user_id}, |
+ path='/p/proj/issues/detail.do?id=%d' % local_id_2, |
+ project=self.project, method='POST', |
+ perms=permissions.USER_PERMISSIONSET) |
+ mr.project_name = self.project.project_name |
+ mr.project = self.project |
+ |
+ # The form should be processed and redirect back to viewing the issue. |
+ redirect_url = self.servlet.ProcessFormData(mr, post_data) |
+ self.assertTrue(redirect_url.startswith( |
+ 'http://127.0.0.1/p/proj/issues/detail?id=%d' % local_id_2)) |
+ |
+ # BUT, issue should not have been edited because user lacked permission. |
+ updated_issue_2 = self.services.issue.GetIssueByLocalID( |
+ self.cnxn, self.project.project_id, local_id_2) |
+ self.assertEqual(local_id_1, updated_issue_2.merged_into) |
+ |
+ notify.PrepareAndSendIssueChangeNotification = orig_prepsend |
+ |
+ def testProcessFormData_DuplicateAddsACommentToTarget(self): |
+ """Marking issue 2 as dup of 1 adds a comment to 1.""" |
+ orig_prepsend = notify.PrepareAndSendIssueChangeNotification |
+ notify.PrepareAndSendIssueChangeNotification = lambda *args, **kwargs: None |
+ orig_get_starrers = tracker_helpers.GetNewIssueStarrers |
+ tracker_helpers.GetNewIssueStarrers = lambda *args, **kwargs: [] |
+ |
+ local_id_1 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_1', 'New', 111L, [], [], [], [], 111L, 'description_1') |
+ issue_1 = self.services.issue.GetIssueByLocalID( |
+ self.cnxn, self.project.project_id, local_id_1) |
+ issue_1.project_name = 'proj' |
+ local_id_2 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_2', 'New', 111L, [], [], [], [], 111L, 'description_2') |
+ issue_2 = self.services.issue.GetIssueByLocalID( |
+ self.cnxn, self.project.project_id, local_id_2) |
+ issue_2.project_name = 'proj' |
+ |
+ post_data = fake.PostData({ |
+ 'status': ['Duplicate'], |
+ 'merge_into': [str(local_id_1)], |
+ 'comment': ['marking as dup'], |
+ 'can': ['1'], |
+ 'q': ['foo'], |
+ 'colspec': ['bar'], |
+ 'sort': 'baz', |
+ 'groupby': 'qux', |
+ 'start': ['0'], |
+ 'num': ['100'], |
+ 'pagegen': [str(int(time.time()) + 1)], |
+ }) |
+ |
+ member_user_id = 111L |
+ _, mr = testing_helpers.GetRequestObjects( |
+ user_info={'user_id': member_user_id}, |
+ path='/p/proj/issues/detail.do?id=%d' % local_id_2, |
+ project=self.project, method='POST', |
+ perms=permissions.COMMITTER_ACTIVE_PERMISSIONSET) |
+ mr.project_name = self.project.project_name |
+ mr.project = self.project |
+ |
+ # The form should be processed and redirect back to viewing the issue. |
+ self.servlet.ProcessFormData(mr, post_data) |
+ |
+ self.assertEqual('Duplicate', issue_2.status) |
+ self.assertEqual(issue_1.issue_id, issue_2.merged_into) |
+ comments_1 = self.services.issue.GetCommentsForIssue( |
+ self.cnxn, issue_1.issue_id) |
+ self.assertEqual(2, len(comments_1)) |
+ self.assertEqual( |
+ 'Issue 2 has been merged into this issue.', |
+ comments_1[1].content) |
+ |
+ # Making another comment on issue 2 does not affect issue 1. |
+ self.servlet.ProcessFormData(mr, post_data) |
+ comments_1 = self.services.issue.GetCommentsForIssue( |
+ self.cnxn, issue_1.issue_id) |
+ self.assertEqual(2, len(comments_1)) |
+ |
+ notify.PrepareAndSendIssueChangeNotification = orig_prepsend |
+ tracker_helpers.GetNewIssueStarrers = orig_get_starrers |
+ |
+ # TODO(jrobbins): add more unit tests for other aspects of ProcessForm. |
+ |
+ |
+class SetStarFormTest(unittest.TestCase): |
+ |
+ def setUp(self): |
+ self.cnxn = 'fake cnxn' |
+ self.services = service_manager.Services( |
+ config=fake.ConfigService(), |
+ issue=fake.IssueService(), |
+ user=fake.UserService(), |
+ project=fake.ProjectService(), |
+ issue_star=fake.IssueStarService()) |
+ self.project = self.services.project.TestAddProject('proj', project_id=987) |
+ self.servlet = issuedetail.SetStarForm( |
+ 'req', 'res', services=self.services) |
+ |
+ def testAssertBasePermission(self): |
+ """Only users with SET_STAR could set star.""" |
+ local_id_1 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
+ _, mr = testing_helpers.GetRequestObjects( |
+ project=self.project, |
+ perms=permissions.READ_ONLY_PERMISSIONSET) |
+ mr.local_id = local_id_1 |
+ self.assertRaises(permissions.PermissionException, |
+ self.servlet.AssertBasePermission, mr) |
+ _, mr = testing_helpers.GetRequestObjects( |
+ project=self.project, |
+ perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET) |
+ mr.local_id = local_id_1 |
+ self.servlet.AssertBasePermission(mr) |
+ |
+ |
+class IssueCommentDeletionTest(unittest.TestCase): |
+ |
+ def setUp(self): |
+ self.cnxn = 'fake cnxn' |
+ self.services = service_manager.Services( |
+ config=fake.ConfigService(), |
+ issue=fake.IssueService(), |
+ user=fake.UserService(), |
+ project=fake.ProjectService(), |
+ issue_star=fake.IssueStarService()) |
+ self.project = self.services.project.TestAddProject('proj', project_id=987) |
+ self.servlet = issuedetail.IssueCommentDeletion( |
+ 'req', 'res', services=self.services) |
+ |
+ def testProcessFormData_Permission(self): |
+ """Permit users who can delete.""" |
+ local_id_1 = self.services.issue.CreateIssue( |
+ self.cnxn, self.services, self.project.project_id, |
+ 'summary_1', 'status', 111L, [], [], [], [], 111L, 'description_1') |
+ _, mr = testing_helpers.GetRequestObjects( |
+ project=self.project, |
+ perms=permissions.READ_ONLY_PERMISSIONSET) |
+ mr.local_id = local_id_1 |
+ mr.auth.user_id = 222L |
+ post_data = { |
+ 'id': local_id_1, |
+ 'sequence_num': 0, |
+ 'mode': 0} |
+ self.assertRaises(permissions.PermissionException, |
+ self.servlet.ProcessFormData, mr, post_data) |
+ _, mr = testing_helpers.GetRequestObjects( |
+ project=self.project, |
+ perms=permissions.OWNER_ACTIVE_PERMISSIONSET) |
+ mr.local_id = local_id_1 |
+ mr.auth.user_id = 222L |
+ self.servlet.ProcessFormData(mr, post_data) |
+ |
+ |
+if __name__ == '__main__': |
+ unittest.main() |