Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1222)

Unified Diff: appengine/monorail/tracker/test/tracker_helpers_test.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/monorail/tracker/test/tracker_helpers_test.py
diff --git a/appengine/monorail/tracker/test/tracker_helpers_test.py b/appengine/monorail/tracker/test/tracker_helpers_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..012bd5ed03ab9a9b29c486f4674a33eeb6d572bd
--- /dev/null
+++ b/appengine/monorail/tracker/test/tracker_helpers_test.py
@@ -0,0 +1,1064 @@
+# 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
+
+"""Unittest for the tracker helpers module."""
+
+import unittest
+
+import settings
+
+from framework import framework_constants
+from framework import framework_helpers
+from framework import permissions
+from framework import template_helpers
+from framework import urls
+from proto import project_pb2
+from proto import tracker_pb2
+from proto import user_pb2
+from services import service_manager
+from testing import fake
+from testing import testing_helpers
+from tracker import tracker_bizobj
+from tracker import tracker_constants
+from tracker import tracker_helpers
+
+TEST_ID_MAP = {
+ 'a@example.com': 1,
+ 'b@example.com': 2,
+ 'c@example.com': 3,
+ 'd@example.com': 4,
+ }
+
+
+def _Issue(project_name, local_id, summary, status):
+ issue = tracker_pb2.Issue()
+ issue.project_name = project_name
+ issue.project_id = 789
+ issue.local_id = local_id
+ issue.issue_id = 100000 + local_id
+ issue.summary = summary
+ issue.status = status
+ return issue
+
+
+def _MakeConfig():
+ config = tracker_pb2.ProjectIssueConfig()
+ config.well_known_statuses.append(tracker_pb2.StatusDef(
+ means_open=True, status='New', deprecated=False))
+ config.well_known_statuses.append(tracker_pb2.StatusDef(
+ status='Old', means_open=False, deprecated=False))
+ config.well_known_statuses.append(tracker_pb2.StatusDef(
+ status='StatusThatWeDontUseAnymore', means_open=False, deprecated=True))
+
+ return config
+
+
+class HelpersTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ config=fake.ConfigService(),
+ issue=fake.IssueService(),
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService())
+
+ for email, user_id in TEST_ID_MAP.iteritems():
+ self.services.user.TestAddUser(email, user_id)
+
+ self.services.project.TestAddProject('testproj', project_id=789)
+ self.issue1 = fake.MakeTestIssue(789, 1, 'one', 'New', 111L)
+ self.issue1.project_name = 'testproj'
+ self.services.issue.TestAddIssue(self.issue1)
+ self.issue2 = fake.MakeTestIssue(789, 2, 'two', 'New', 111L)
+ self.issue2.project_name = 'testproj'
+ self.services.issue.TestAddIssue(self.issue2)
+ self.issue3 = fake.MakeTestIssue(789, 3, 'three', 'New', 111L)
+ self.issue3.project_name = 'testproj'
+ self.services.issue.TestAddIssue(self.issue3)
+ self.cnxn = 'fake connextion'
+ self.errors = template_helpers.EZTError()
+ self.default_colspec_param = 'colspec=%s' % (
+ tracker_constants.DEFAULT_COL_SPEC.replace(' ', '%20'))
+ self.services.usergroup.TestAddGroupSettings(999L, 'group@example.com')
+
+ def testParseIssueRequest_Empty(self):
+ post_data = fake.PostData()
+ errors = template_helpers.EZTError()
+ parsed = tracker_helpers.ParseIssueRequest(
+ 'fake cnxn', post_data, self.services, errors, 'proj')
+ self.assertEqual('', parsed.summary)
+ self.assertEqual('', parsed.comment)
+ self.assertEqual('', parsed.status)
+ self.assertEqual('', parsed.users.owner_username)
+ self.assertEqual(0, parsed.users.owner_id)
+ self.assertEqual([], parsed.users.cc_usernames)
+ self.assertEqual([], parsed.users.cc_usernames_remove)
+ self.assertEqual([], parsed.users.cc_ids)
+ self.assertEqual([], parsed.users.cc_ids_remove)
+ self.assertEqual('', parsed.template_name)
+ self.assertEqual([], parsed.labels)
+ self.assertEqual([], parsed.labels_remove)
+ self.assertEqual({}, parsed.fields.vals)
+ self.assertEqual({}, parsed.fields.vals_remove)
+ self.assertEqual([], parsed.fields.fields_clear)
+ self.assertEqual('', parsed.blocked_on.entered_str)
+ self.assertEqual([], parsed.blocked_on.iids)
+
+ def testParseIssueRequest_Normal(self):
+ post_data = fake.PostData({
+ 'summary': ['some summary'],
+ 'comment': ['some comment'],
+ 'status': ['SomeStatus'],
+ 'template_name': ['some template'],
+ 'label': ['lab1', '-lab2'],
+ 'custom_123': ['field1123a', 'field1123b'],
+ })
+ errors = template_helpers.EZTError()
+ parsed = tracker_helpers.ParseIssueRequest(
+ 'fake cnxn', post_data, self.services, errors, 'proj')
+ self.assertEqual('some summary', parsed.summary)
+ self.assertEqual('some comment', parsed.comment)
+ self.assertEqual('SomeStatus', parsed.status)
+ self.assertEqual('', parsed.users.owner_username)
+ self.assertEqual(0, parsed.users.owner_id)
+ self.assertEqual([], parsed.users.cc_usernames)
+ self.assertEqual([], parsed.users.cc_usernames_remove)
+ self.assertEqual([], parsed.users.cc_ids)
+ self.assertEqual([], parsed.users.cc_ids_remove)
+ self.assertEqual('some template', parsed.template_name)
+ self.assertEqual(['lab1'], parsed.labels)
+ self.assertEqual(['lab2'], parsed.labels_remove)
+ self.assertEqual({123: ['field1123a', 'field1123b']}, parsed.fields.vals)
+ self.assertEqual({}, parsed.fields.vals_remove)
+ self.assertEqual([], parsed.fields.fields_clear)
+
+ def testParseBlockers_BlockedOnNothing(self):
+ """Was blocked on nothing, still nothing."""
+ post_data = {tracker_helpers.BLOCKED_ON: ''}
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKED_ON)
+
+ self.assertEqual('', parsed_blockers.entered_str)
+ self.assertEqual([], parsed_blockers.iids)
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
+
+ def testParseBlockers_BlockedOnAdded(self):
+ """Was blocked on nothing; now 1, 2, 3."""
+ post_data = {tracker_helpers.BLOCKED_ON: '1, 2, 3'}
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKED_ON)
+
+ self.assertEqual('1, 2, 3', parsed_blockers.entered_str)
+ self.assertEqual([100001, 100002, 100003], parsed_blockers.iids)
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
+
+ def testParseBlockers_BlockedOnDuplicateRef(self):
+ """Was blocked on nothing; now just 2, but repeated in input."""
+ post_data = {tracker_helpers.BLOCKED_ON: '2, 2, 2'}
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKED_ON)
+
+ self.assertEqual('2, 2, 2', parsed_blockers.entered_str)
+ self.assertEqual([100002], parsed_blockers.iids)
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
+
+ def testParseBlockers_Missing(self):
+ """Parsing an input field that was not in the POST."""
+ post_data = {}
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKED_ON)
+
+ self.assertEqual('', parsed_blockers.entered_str)
+ self.assertEqual([], parsed_blockers.iids)
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
+
+ def testParseBlockers_SameIssueNoProject(self):
+ """Adding same issue as blocker should modify the errors object."""
+ post_data = {'id': '2', tracker_helpers.BLOCKING: '2, 3'}
+
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKING)
+ self.assertEqual('2, 3', parsed_blockers.entered_str)
+ self.assertEqual([], parsed_blockers.iids)
+ self.assertEqual(
+ getattr(self.errors, tracker_helpers.BLOCKING),
+ 'Cannot be blocking the same issue')
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+
+ def testParseBlockers_SameIssueSameProject(self):
+ """Adding same issue as blocker should modify the errors object."""
+ post_data = {'id': '2', tracker_helpers.BLOCKING: 'testproj:2, 3'}
+
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKING)
+ self.assertEqual('testproj:2, 3', parsed_blockers.entered_str)
+ self.assertEqual([], parsed_blockers.iids)
+ self.assertEqual(
+ getattr(self.errors, tracker_helpers.BLOCKING),
+ 'Cannot be blocking the same issue')
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+
+ def testParseBlockers_SameIssueDifferentProject(self):
+ """Adding different blocker issue should not modify the errors object."""
+ post_data = {'id': '2', tracker_helpers.BLOCKING: 'testproj:2'}
+
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testprojB',
+ tracker_helpers.BLOCKING)
+ self.assertEqual('testproj:2', parsed_blockers.entered_str)
+ self.assertEqual([100002], parsed_blockers.iids)
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+
+ def testParseBlockers_Invalid(self):
+ """Input fields with invalid values should modify the errors object."""
+ post_data = {tracker_helpers.BLOCKING: '2, foo',
+ tracker_helpers.BLOCKED_ON: '3, bar'}
+
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKING)
+ self.assertEqual('2, foo', parsed_blockers.entered_str)
+ self.assertEqual([100002], parsed_blockers.iids)
+ self.assertEqual(
+ getattr(self.errors, tracker_helpers.BLOCKING), 'Invalid issue ID foo')
+ self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
+
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKED_ON)
+ self.assertEqual('3, bar', parsed_blockers.entered_str)
+ self.assertEqual([100003], parsed_blockers.iids)
+ self.assertEqual(
+ getattr(self.errors, tracker_helpers.BLOCKED_ON),
+ 'Invalid issue ID bar')
+
+ def testParseBlockers_Dangling(self):
+ """A ref to a sanctioned projected should be allowed."""
+ post_data = {'id': '2', tracker_helpers.BLOCKING: 'otherproj:2'}
+ real_codesite_projects = settings.recognized_codesite_projects
+ settings.recognized_codesite_projects = ['otherproj']
+ parsed_blockers = tracker_helpers._ParseBlockers(
+ self.cnxn, post_data, self.services, self.errors, 'testproj',
+ tracker_helpers.BLOCKING)
+ self.assertEqual('otherproj:2', parsed_blockers.entered_str)
+ self.assertEqual([('otherproj', 2)], parsed_blockers.dangling_refs)
+ settings.recognized_codesite_projects = real_codesite_projects
+
+ def testMeansOpenInProject(self):
+ config = _MakeConfig()
+
+ # ensure open means open
+ self.assertTrue(tracker_helpers.MeansOpenInProject('New', config))
+ self.assertTrue(tracker_helpers.MeansOpenInProject('new', config))
+
+ # ensure an unrecognized status means open
+ self.assertTrue(tracker_helpers.MeansOpenInProject(
+ '_undefined_status_', config))
+
+ # ensure closed means closed
+ self.assertFalse(tracker_helpers.MeansOpenInProject('Old', config))
+ self.assertFalse(tracker_helpers.MeansOpenInProject('old', config))
+ self.assertFalse(tracker_helpers.MeansOpenInProject(
+ 'StatusThatWeDontUseAnymore', config))
+
+ def testIsNoisy(self):
+ self.assertTrue(tracker_helpers.IsNoisy(778, 320))
+ self.assertFalse(tracker_helpers.IsNoisy(20, 500))
+ self.assertFalse(tracker_helpers.IsNoisy(500, 20))
+ self.assertFalse(tracker_helpers.IsNoisy(1, 1))
+
+ def testClassifyPlusMinusItems(self):
+ add, remove = tracker_helpers._ClassifyPlusMinusItems([])
+ self.assertEquals([], add)
+ self.assertEquals([], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['', ' ', ' \t', '-'])
+ self.assertItemsEqual([], add)
+ self.assertItemsEqual([], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['a', 'b', 'c'])
+ self.assertItemsEqual(['a', 'b', 'c'], add)
+ self.assertItemsEqual([], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['a-a-a', 'b-b', 'c-'])
+ self.assertItemsEqual(['a-a-a', 'b-b', 'c-'], add)
+ self.assertItemsEqual([], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['-a'])
+ self.assertItemsEqual([], add)
+ self.assertItemsEqual(['a'], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['-a', 'b', 'c-c'])
+ self.assertItemsEqual(['b', 'c-c'], add)
+ self.assertItemsEqual(['a'], remove)
+
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['-a', '-b-b', '-c-'])
+ self.assertItemsEqual([], add)
+ self.assertItemsEqual(['a', 'b-b', 'c-'], remove)
+
+ # We dedup, but we don't cancel out items that are both added and removed.
+ add, remove = tracker_helpers._ClassifyPlusMinusItems(
+ ['a', 'a', '-a'])
+ self.assertItemsEqual(['a'], add)
+ self.assertItemsEqual(['a'], remove)
+
+ def testParseIssueRequestAttachments(self):
+ file1 = testing_helpers.Blank(
+ filename='hello.c',
+ value='hello world')
+
+ file2 = testing_helpers.Blank(
+ filename='README',
+ value='Welcome to our project')
+
+ file3 = testing_helpers.Blank(
+ filename='c:\\dir\\subdir\\FILENAME.EXT',
+ value='Abort, Retry, or Fail?')
+
+ # Browsers send this if FILE field was not filled in.
+ file4 = testing_helpers.Blank(
+ filename='',
+ value='')
+
+ attachments = tracker_helpers._ParseIssueRequestAttachments({})
+ self.assertEquals([], attachments)
+
+ attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
+ 'file1': [file1],
+ }))
+ self.assertEquals(
+ [('hello.c', 'hello world', 'text/plain')],
+ attachments)
+
+ attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
+ 'file1': [file1],
+ 'file2': [file2],
+ }))
+ self.assertEquals(
+ [('hello.c', 'hello world', 'text/plain'),
+ ('README', 'Welcome to our project', 'text/plain')],
+ attachments)
+
+ attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
+ 'file3': [file3],
+ }))
+ self.assertEquals(
+ [('FILENAME.EXT', 'Abort, Retry, or Fail?',
+ 'application/octet-stream')],
+ attachments)
+
+ attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
+ 'file1': [file4], # Does not appear in result
+ 'file3': [file3],
+ 'file4': [file4], # Does not appear in result
+ }))
+ self.assertEquals(
+ [('FILENAME.EXT', 'Abort, Retry, or Fail?',
+ 'application/octet-stream')],
+ attachments)
+
+ def testParseIssueRequestUsers(self):
+ post_data = {}
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('', parsed_users.owner_username)
+ self.assertEquals(
+ framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
+ self.assertEquals([], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'owner': [''],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('', parsed_users.owner_username)
+ self.assertEquals(
+ framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
+ self.assertEquals([], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'owner': [' \t'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('', parsed_users.owner_username)
+ self.assertEquals(
+ framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
+ self.assertEquals([], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'owner': ['b@example.com'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('b@example.com', parsed_users.owner_username)
+ self.assertEquals(TEST_ID_MAP['b@example.com'], parsed_users.owner_id)
+ self.assertEquals([], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'owner': ['b@example.com'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('b@example.com', parsed_users.owner_username)
+ self.assertEquals(TEST_ID_MAP['b@example.com'], parsed_users.owner_id)
+ self.assertEquals([], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'cc': ['b@example.com'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('', parsed_users.owner_username)
+ self.assertEquals(
+ framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
+ self.assertEquals(['b@example.com'], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertEquals([TEST_ID_MAP['b@example.com']], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'cc': ['-b@example.com, c@example.com,,'
+ 'a@example.com,'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('', parsed_users.owner_username)
+ self.assertEquals(
+ framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
+ self.assertItemsEqual(['c@example.com', 'a@example.com'],
+ parsed_users.cc_usernames)
+ self.assertEquals(['b@example.com'], parsed_users.cc_usernames_remove)
+ self.assertItemsEqual([TEST_ID_MAP['c@example.com'],
+ TEST_ID_MAP['a@example.com']],
+ parsed_users.cc_ids)
+ self.assertEquals([TEST_ID_MAP['b@example.com']],
+ parsed_users.cc_ids_remove)
+
+ post_data = fake.PostData({
+ 'owner': ['fuhqwhgads@example.com'],
+ 'cc': ['c@example.com, fuhqwhgads@example.com'],
+ })
+ parsed_users = tracker_helpers._ParseIssueRequestUsers(
+ 'fake connection', post_data, self.services)
+ self.assertEquals('fuhqwhgads@example.com', parsed_users.owner_username)
+ gen_uid = framework_helpers.MurmurHash3_x86_32(parsed_users.owner_username)
+ self.assertEquals(gen_uid, parsed_users.owner_id) # autocreated user
+ self.assertItemsEqual(
+ ['c@example.com', 'fuhqwhgads@example.com'], parsed_users.cc_usernames)
+ self.assertEquals([], parsed_users.cc_usernames_remove)
+ self.assertItemsEqual(
+ [TEST_ID_MAP['c@example.com'], gen_uid], parsed_users.cc_ids)
+ self.assertEquals([], parsed_users.cc_ids_remove)
+
+ def testIsValidIssueOwner(self):
+ project = project_pb2.Project()
+ project.owner_ids.extend([1L, 2L])
+ project.committer_ids.extend([3L])
+ project.contributor_ids.extend([4L, 999L])
+
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, framework_constants.NO_USER_SPECIFIED,
+ self.services)
+ self.assertTrue(valid)
+
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 1L,
+ self.services)
+ self.assertTrue(valid)
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 2L,
+ self.services)
+ self.assertTrue(valid)
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 3L,
+ self.services)
+ self.assertTrue(valid)
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 4L,
+ self.services)
+ self.assertTrue(valid)
+
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 7L,
+ self.services)
+ self.assertFalse(valid)
+
+ valid, _ = tracker_helpers.IsValidIssueOwner(
+ 'fake cnxn', project, 999L,
+ self.services)
+ self.assertFalse(valid)
+
+ def testGetAllowedOpenAndClosedRelatedIssues(self):
+ gaoacri = tracker_helpers.GetAllowedOpenAndClosedRelatedIssues
+ opened = {
+ 100001: _Issue('proj', 1, 'summary 1', 'New'),
+ 100002: _Issue('proj', 2, 'summary 2', 'Accepted'),
+ }
+ closed = {
+ 100003: _Issue('proj', 3, 'summary 3', 'Accepted'),
+ 100004: _Issue('proj', 4, 'summary 4', 'Invalid'),
+ }
+ project = project_pb2.Project()
+ project.project_id = 789
+ project.project_name = 'proj'
+ project.state = project_pb2.ProjectState.LIVE
+ mr = testing_helpers.MakeMonorailRequest(project=project)
+ fake_issue_service = testing_helpers.Blank(
+ GetOpenAndClosedIssues=lambda _cnxn, iids: (
+ [opened[iid] for iid in iids if iid in opened],
+ [closed[iid] for iid in iids if iid in closed]))
+ fake_config_service = testing_helpers.Blank(
+ GetProjectConfigs=lambda _cnxn, pids: (
+ {pid: tracker_bizobj.MakeDefaultProjectIssueConfig(pid)
+ for pid in pids}))
+ fake_project_service = testing_helpers.Blank(
+ GetProjects=lambda _, project_ids: {project.project_id: project})
+ services = service_manager.Services(
+ issue=fake_issue_service, config=fake_config_service,
+ project=fake_project_service)
+
+ issue = tracker_pb2.Issue()
+ issue.project_id = 789
+ # No merged into, no blocking, no blocked on.
+ open_dict, closed_dict = gaoacri(services, mr, issue)
+ self.assertEqual({}, open_dict)
+ self.assertEqual({}, closed_dict)
+
+ # An open "merged into"
+ issue.merged_into = 100001
+ open_dict, closed_dict = gaoacri(services, mr, issue)
+ self.assertEqual({100001: opened[100001]}, open_dict)
+ self.assertEqual({}, closed_dict)
+
+ # A closed "merged into"
+ issue.merged_into = 100003
+ open_dict, closed_dict = gaoacri(services, mr, issue)
+ self.assertEqual({}, open_dict)
+ self.assertEqual({100003: closed[100003]}, closed_dict)
+
+ # Some blocking and blocked on
+ issue.blocking_iids.append(100001)
+ issue.blocked_on_iids.append(100004)
+ open_dict, closed_dict = gaoacri(services, mr, issue)
+ self.assertEqual({100001: opened[100001]}, open_dict)
+ self.assertEqual({100003: closed[100003],
+ 100004: closed[100004]}, closed_dict)
+
+ def testMergeCCsAndAddComment(self):
+ target_issue = fake.MakeTestIssue(
+ 789, 10, 'Target issue', 'New', 111L)
+ source_issue = fake.MakeTestIssue(
+ 789, 100, 'Source issue', 'New', 222L)
+ source_issue.cc_ids.append(111L)
+ # Issue without owner
+ source_issue_2 = fake.MakeTestIssue(
+ 789, 101, 'Source issue 2', 'New', 0L)
+
+ project = self.services.project.TestAddProject(
+ 'testproj', owner_ids=[222L], project_id=789)
+ self.services.issue.TestAddIssue(target_issue)
+ self.services.issue.TestAddIssue(source_issue)
+ self.services.issue.TestAddIssue(source_issue_2)
+
+ # We copy this list so that it isn't updated by the test framework
+ initial_issue_comments = (
+ self.services.issue.GetCommentsForIssue(
+ 'fake cnxn', target_issue.issue_id)[:])
+ mr = testing_helpers.MakeMonorailRequest(user_info={'user_id': 111L})
+
+ # Merging source into target should create a comment.
+ self.assertIsNotNone(
+ tracker_helpers.MergeCCsAndAddComment(
+ self.services, mr, source_issue, project, target_issue))
+ updated_issue_comments = self.services.issue.GetCommentsForIssue(
+ 'fake cnxn', target_issue.issue_id)
+ for comment in initial_issue_comments:
+ self.assertIn(comment, updated_issue_comments)
+ self.assertEqual(
+ len(initial_issue_comments) + 1, len(updated_issue_comments))
+
+ # Merging source into target should add source's owner to target's CCs.
+ updated_target_issue = self.services.issue.GetIssueByLocalID(
+ 'fake cnxn', 789, 10)
+ self.assertIn(111L, updated_target_issue.cc_ids)
+ self.assertIn(222L, updated_target_issue.cc_ids)
+
+ # Merging source 2 into target should make a comment, but not update CCs.
+ self.assertIsNotNone(
+ tracker_helpers.MergeCCsAndAddComment(
+ self.services, mr, source_issue_2, project, updated_target_issue))
+ updated_target_issue = self.services.issue.GetIssueByLocalID(
+ 'fake cnxn', 789, 10)
+ self.assertNotIn(0L, updated_target_issue.cc_ids)
+
+ def testMergeCCsAndAddCommentRestrictedSourceIssue(self):
+ target_issue = fake.MakeTestIssue(
+ 789, 10, 'Target issue', 'New', 222L)
+ target_issue_2 = fake.MakeTestIssue(
+ 789, 11, 'Target issue 2', 'New', 222L)
+ source_issue = fake.MakeTestIssue(
+ 789, 100, 'Source issue', 'New', 111L)
+ source_issue.cc_ids.append(111L)
+ source_issue.labels.append('Restrict-View-Commit')
+ target_issue_2.labels.append('Restrict-View-Commit')
+
+ project = self.services.project.TestAddProject(
+ 'testproj', owner_ids=[222L], project_id=789)
+ self.services.issue.TestAddIssue(source_issue)
+ self.services.issue.TestAddIssue(target_issue)
+ self.services.issue.TestAddIssue(target_issue_2)
+
+ # We copy this list so that it isn't updated by the test framework
+ initial_issue_comments = self.services.issue.GetCommentsForIssue(
+ 'fake cnxn', target_issue.issue_id)[:]
+ mr = testing_helpers.MakeMonorailRequest(user_info={'user_id': 111L})
+ self.assertIsNotNone(
+ tracker_helpers.MergeCCsAndAddComment(
+ self.services, mr, source_issue, project, target_issue))
+
+ # When the source is restricted, we update the target comments...
+ updated_issue_comments = self.services.issue.GetCommentsForIssue(
+ 'fake cnxn', target_issue.issue_id)
+ for comment in initial_issue_comments:
+ self.assertIn(comment, updated_issue_comments)
+ self.assertEqual(
+ len(initial_issue_comments) + 1, len(updated_issue_comments))
+ # ...but not the target CCs...
+ updated_target_issue = self.services.issue.GetIssueByLocalID(
+ 'fake cnxn', 789, 10)
+ self.assertNotIn(111L, updated_target_issue.cc_ids)
+ # ...unless both issues have the same restrictions.
+ self.assertIsNotNone(
+ tracker_helpers.MergeCCsAndAddComment(
+ self.services, mr, source_issue, project, target_issue_2))
+ updated_target_issue_2 = self.services.issue.GetIssueByLocalID(
+ 'fake cnxn', 789, 11)
+ self.assertIn(111L, updated_target_issue_2.cc_ids)
+
+ def testFormatIssueListURLNoCurrentState(self):
+ config = tracker_pb2.ProjectIssueConfig()
+ path = '/p/proj/issues/detail?id=123'
+ mr = testing_helpers.MakeMonorailRequest(
+ path=path, headers={'Host': 'code.google.com'})
+ mr.ComputeColSpec(config)
+
+ absolute_base_url = 'http://code.google.com'
+
+ url_1 = tracker_helpers.FormatIssueListURL(mr, config)
+ self.assertEquals(
+ '%s/p/proj/issues/list?%s' % (
+ absolute_base_url, self.default_colspec_param),
+ url_1)
+
+ url_2 = tracker_helpers.FormatIssueListURL(
+ mr, config, foo=123)
+ self.assertEquals(
+ '%s/p/proj/issues/list?%s&foo=123' % (
+ absolute_base_url, self.default_colspec_param),
+ url_2)
+
+ url_3 = tracker_helpers.FormatIssueListURL(
+ mr, config, foo=123, bar='abc')
+ self.assertEquals(
+ '%s/p/proj/issues/list?bar=abc&%s&foo=123' % (
+ absolute_base_url, self.default_colspec_param),
+ url_3)
+
+ url_4 = tracker_helpers.FormatIssueListURL(
+ mr, config, baz='escaped+encoded&and100% "safe"')
+ self.assertEquals(
+ '%s/p/proj/issues/list?'
+ 'baz=escaped%%2Bencoded%%26and100%%25%%20%%22safe%%22&%s' % (
+ absolute_base_url, self.default_colspec_param),
+ url_4)
+
+ def testFormatIssueListURLKeepCurrentState(self):
+ config = tracker_pb2.ProjectIssueConfig()
+ path = '/p/proj/issues/detail?id=123&sort=aa&colspec=a b c&groupby=d'
+ mr = testing_helpers.MakeMonorailRequest(
+ path=path, headers={'Host': 'localhost:8080'})
+ mr.ComputeColSpec(config)
+
+ absolute_base_url = 'http://localhost:8080'
+
+ url_1 = tracker_helpers.FormatIssueListURL(mr, config)
+ self.assertEquals(
+ '%s/p/proj/issues/list?colspec=a%%20b%%20c'
+ '&groupby=d&sort=aa' % absolute_base_url,
+ url_1)
+
+ url_2 = tracker_helpers.FormatIssueListURL(
+ mr, config, foo=123)
+ self.assertEquals(
+ '%s/p/proj/issues/list?'
+ 'colspec=a%%20b%%20c&foo=123&groupby=d&sort=aa' % absolute_base_url,
+ url_2)
+
+ url_3 = tracker_helpers.FormatIssueListURL(
+ mr, config, colspec='X Y Z')
+ self.assertEquals(
+ '%s/p/proj/issues/list?colspec=a%%20b%%20c'
+ '&groupby=d&sort=aa' % absolute_base_url,
+ url_3)
+
+ def testFormatRelativeIssueURL(self):
+ self.assertEquals(
+ '/p/proj/issues/attachment',
+ tracker_helpers.FormatRelativeIssueURL(
+ 'proj', urls.ISSUE_ATTACHMENT))
+
+ self.assertEquals(
+ '/p/proj/issues/detail?id=123',
+ tracker_helpers.FormatRelativeIssueURL(
+ 'proj', urls.ISSUE_DETAIL, id=123))
+
+
+class MakeViewsForUsersInIssuesTest(unittest.TestCase):
+
+ def setUp(self):
+ self.issue1 = _Issue('proj', 1, 'summary 1', 'New')
+ self.issue1.owner_id = 1001
+ self.issue1.reporter_id = 1002
+
+ self.issue2 = _Issue('proj', 2, 'summary 2', 'New')
+ self.issue2.owner_id = 2001
+ self.issue2.reporter_id = 2002
+ self.issue2.cc_ids.extend([1, 1001, 1002, 1003])
+
+ self.issue3 = _Issue('proj', 3, 'summary 3', 'New')
+ self.issue3.owner_id = 1001
+ self.issue3.reporter_id = 3002
+
+ self.user = fake.UserService()
+ for user_id in [1, 1001, 1002, 1003, 2001, 2002, 3002]:
+ self.user.TestAddUser(
+ 'test%d' % user_id, user_id, add_user=True)
+
+ def testMakeViewsForUsersInIssues(self):
+ issue_list = [self.issue1, self.issue2, self.issue3]
+ users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
+ 'fake cnxn', issue_list, self.user)
+ self.assertItemsEqual([1, 1001, 1002, 1003, 2001, 2002, 3002],
+ users_by_id.keys())
+ for user_id in [1001, 1002, 1003, 2001]:
+ self.assertEqual(users_by_id[user_id].user_id, user_id)
+
+ def testMakeViewsForUsersInIssuesOmittingSome(self):
+ issue_list = [self.issue1, self.issue2, self.issue3]
+ users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
+ 'fake cnxn', issue_list, self.user, omit_ids=[1001, 1003])
+ self.assertItemsEqual([1, 1002, 2001, 2002, 3002], users_by_id.keys())
+ for user_id in [1002, 2001, 2002, 3002]:
+ self.assertEqual(users_by_id[user_id].user_id, user_id)
+
+ def testMakeViewsForUsersInIssuesEmpty(self):
+ issue_list = []
+ users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
+ 'fake cnxn', issue_list, self.user)
+ self.assertItemsEqual([], users_by_id.keys())
+
+
+class GetAllIssueProjectsTest(unittest.TestCase):
+ issue_x_1 = tracker_pb2.Issue()
+ issue_x_1.project_id = 789
+ issue_x_1.local_id = 1
+ issue_x_1.reporter_id = 1002
+
+ issue_x_2 = tracker_pb2.Issue()
+ issue_x_2.project_id = 789
+ issue_x_2.local_id = 2
+ issue_x_2.reporter_id = 2002
+
+ issue_y_1 = tracker_pb2.Issue()
+ issue_y_1.project_id = 678
+ issue_y_1.local_id = 1
+ issue_y_1.reporter_id = 2002
+
+ def setUp(self):
+ self.project_service = fake.ProjectService()
+ self.project_service.TestAddProject('proj-x', project_id=789)
+ self.project_service.TestAddProject('proj-y', project_id=678)
+ self.cnxn = 'fake connection'
+
+ def testGetAllIssueProjects_Empty(self):
+ self.assertEqual(
+ {}, tracker_helpers.GetAllIssueProjects(
+ self.cnxn, [], self.project_service))
+
+ def testGetAllIssueProjects_Normal(self):
+ self.assertEqual(
+ {789: self.project_service.GetProjectByName(self.cnxn, 'proj-x')},
+ tracker_helpers.GetAllIssueProjects(
+ self.cnxn, [self.issue_x_1, self.issue_x_2], self.project_service))
+ self.assertEqual(
+ {789: self.project_service.GetProjectByName(self.cnxn, 'proj-x'),
+ 678: self.project_service.GetProjectByName(self.cnxn, 'proj-y')},
+ tracker_helpers.GetAllIssueProjects(
+ self.cnxn, [self.issue_x_1, self.issue_x_2, self.issue_y_1],
+ self.project_service))
+
+
+class FilterOutNonViewableIssuesTest(unittest.TestCase):
+ owner_id = 111L
+ committer_id = 222L
+ nonmember_1_id = 1002L
+ nonmember_2_id = 2002L
+ nonmember_3_id = 3002L
+
+ issue1 = tracker_pb2.Issue()
+ issue1.project_name = 'proj'
+ issue1.project_id = 789
+ issue1.local_id = 1
+ issue1.reporter_id = nonmember_1_id
+
+ issue2 = tracker_pb2.Issue()
+ issue2.project_name = 'proj'
+ issue2.project_id = 789
+ issue2.local_id = 2
+ issue2.reporter_id = nonmember_2_id
+ issue2.labels.extend(['foo', 'bar'])
+
+ issue3 = tracker_pb2.Issue()
+ issue3.project_name = 'proj'
+ issue3.project_id = 789
+ issue3.local_id = 3
+ issue3.reporter_id = nonmember_3_id
+ issue3.labels.extend(['restrict-view-commit'])
+
+ issue4 = tracker_pb2.Issue()
+ issue4.project_name = 'proj'
+ issue4.project_id = 789
+ issue4.local_id = 4
+ issue4.reporter_id = nonmember_3_id
+ issue4.labels.extend(['Foo', 'Restrict-View-Commit'])
+
+ def setUp(self):
+ self.user = user_pb2.User()
+ self.project = self.MakeProject(project_pb2.ProjectState.LIVE)
+ self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(
+ self.project.project_id)
+ self.project_dict = {self.project.project_id: self.project}
+ self.config_dict = {self.config.project_id: self.config}
+
+ def MakeProject(self, state):
+ p = project_pb2.Project(
+ project_id=789, project_name='proj', state=state,
+ owner_ids=[self.owner_id], committer_ids=[self.committer_id])
+ return p
+
+ def testFilterOutNonViewableIssues_Member(self):
+ # perms will be permissions.COMMITTER_ACTIVE_PERMISSIONSET
+ filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
+ {self.committer_id}, self.user, self.project_dict,
+ self.config_dict,
+ [self.issue1, self.issue2, self.issue3, self.issue4])
+ self.assertListEqual([1, 2, 3, 4],
+ [issue.local_id for issue in filtered_issues])
+
+ def testFilterOutNonViewableIssues_Owner(self):
+ # perms will be permissions.OWNER_ACTIVE_PERMISSIONSET
+ filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
+ {self.owner_id}, self.user, self.project_dict, self.config_dict,
+ [self.issue1, self.issue2, self.issue3, self.issue4])
+ self.assertListEqual([1, 2, 3, 4],
+ [issue.local_id for issue in filtered_issues])
+
+ def testFilterOutNonViewableIssues_Empty(self):
+ # perms will be permissions.COMMITTER_ACTIVE_PERMISSIONSET
+ filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
+ {self.committer_id}, self.user, self.project_dict,
+ self.config_dict, [])
+ self.assertListEqual([], filtered_issues)
+
+ def testFilterOutNonViewableIssues_NonMember(self):
+ # perms will be permissions.READ_ONLY_PERMISSIONSET
+ filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
+ {self.nonmember_1_id}, self.user, self.project_dict,
+ self.config_dict, [self.issue1, self.issue2, self.issue3, self.issue4])
+ self.assertListEqual([1, 2],
+ [issue.local_id for issue in filtered_issues])
+
+ def testFilterOutNonViewableIssues_Reporter(self):
+ # perms will be permissions.READ_ONLY_PERMISSIONSET
+ filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
+ {self.nonmember_3_id}, self.user, self.project_dict,
+ self.config_dict, [self.issue1, self.issue2, self.issue3, self.issue4])
+ self.assertListEqual([1, 2, 3, 4],
+ [issue.local_id for issue in filtered_issues])
+
+
+class IssueMergeTest(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_bizobj.MakeDefaultProjectIssueConfig(
+ self.project.project_id)
+ self.project_dict = {self.project.project_id: self.project}
+ self.config_dict = {self.config.project_id: self.config}
+
+ def testParseMergeFields_NotSpecified(self):
+ issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
+ errors = template_helpers.EZTError()
+ post_data = {}
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, None, 'proj', post_data, 'New', self.config, issue, errors)
+ self.assertEqual('', text)
+ self.assertEqual(None, merge_into_issue)
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, None, 'proj', post_data, 'Duplicate', self.config, issue,
+ errors)
+ self.assertEqual('', text)
+ self.assertTrue(errors.merge_into_id)
+ self.assertEqual(None, merge_into_issue)
+
+ def testParseMergeFields_WrongStatus(self):
+ issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
+ errors = template_helpers.EZTError()
+ post_data = {'merge_into': '12'}
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, None, 'proj', post_data, 'New', self.config, issue, errors)
+ self.assertEqual('', text)
+ self.assertEqual(None, merge_into_issue)
+
+ def testParseMergeFields_NoSuchIssue(self):
+ issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
+ issue.merged_into = 12
+ errors = template_helpers.EZTError()
+ post_data = {'merge_into': '12'}
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, self.services, 'proj', post_data, 'Duplicate',
+ self.config, issue, errors)
+ self.assertEqual('12', text)
+ self.assertEqual(None, merge_into_issue)
+
+ def testParseMergeFields_DontSelfMerge(self):
+ issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
+ errors = template_helpers.EZTError()
+ post_data = {'merge_into': '1'}
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, self.services, 'proj', post_data, 'Duplicate', self.config,
+ issue, errors)
+ self.assertEqual('1', text)
+ self.assertEqual(None, merge_into_issue)
+ self.assertEqual('Cannot merge issue into itself', errors.merge_into_id)
+
+ def testParseMergeFields_NewIssueToMerge(self):
+ merged_local_id = self.services.issue.CreateIssue(
+ self.cnxn, self.services,
+ self.project.project_id, 'unused_summary', 'unused_status', 111L,
+ [], [], [], [], 111L, 'unused_marked_description')
+ mergee_local_id = self.services.issue.CreateIssue(
+ self.cnxn, self.services,
+ self.project.project_id, 'unused_summary', 'unused_status', 111L,
+ [], [], [], [], 111L, 'unused_marked_description')
+ merged_issue = self.services.issue.GetIssueByLocalID(
+ self.cnxn, self.project.project_id, merged_local_id)
+ mergee_issue = self.services.issue.GetIssueByLocalID(
+ self.cnxn, self.project.project_id, mergee_local_id)
+
+ errors = template_helpers.EZTError()
+ post_data = {'merge_into': str(mergee_issue.local_id)}
+
+ text, merge_into_issue = tracker_helpers.ParseMergeFields(
+ self.cnxn, self.services, 'proj', post_data, 'Duplicate', self.config,
+ merged_issue, errors)
+ self.assertEqual(str(mergee_issue.local_id), text)
+ self.assertEqual(mergee_issue, merge_into_issue)
+
+ def testIsMergeAllowed(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
+ issue.project_name = self.project.project_name
+
+ for (perm_set, expected_merge_allowed) in (
+ (permissions.READ_ONLY_PERMISSIONSET, False),
+ (permissions.COMMITTER_INACTIVE_PERMISSIONSET, False),
+ (permissions.COMMITTER_ACTIVE_PERMISSIONSET, True),
+ (permissions.OWNER_ACTIVE_PERMISSIONSET, True)):
+ mr.perms = perm_set
+ merge_allowed = tracker_helpers.IsMergeAllowed(issue, mr, self.services)
+ self.assertEquals(expected_merge_allowed, merge_allowed)
+
+ def testMergeIssueStars(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.project_name = self.project.project_name
+ mr.project = self.project
+
+ config = self.services.config.GetProjectConfig(
+ self.cnxn, self.project.project_id)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 1, 1, True)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 1, 2, True)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 1, 3, True)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 2, 3, True)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 2, 4, True)
+ self.services.issue_star.SetStar(
+ self.cnxn, self.services, config, 2, 5, True)
+
+ new_starrers = tracker_helpers.GetNewIssueStarrers(
+ self.cnxn, self.services, 1, 2)
+ self.assertItemsEqual(new_starrers, [1, 2])
+ tracker_helpers.AddIssueStarrers(
+ self.cnxn, self.services, mr, 2, self.project, new_starrers)
+ issue_2_starrers = self.services.issue_star.LookupItemStarrers(
+ self.cnxn, 2)
+ # XXX(jrobbins): these tests incorrectly mix local IDs with IIDs.
+ self.assertItemsEqual([1, 2, 3, 4, 5], issue_2_starrers)
+
+
+if __name__ == '__main__':
+ unittest.main()
« no previous file with comments | « appengine/monorail/tracker/test/tracker_bizobj_test.py ('k') | appengine/monorail/tracker/test/tracker_views_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698