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

Side by Side 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 unified diff | Download patch
OLDNEW
(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 """Unittest for the tracker helpers module."""
7
8 import unittest
9
10 import settings
11
12 from framework import framework_constants
13 from framework import framework_helpers
14 from framework import permissions
15 from framework import template_helpers
16 from framework import urls
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 testing import fake
22 from testing import testing_helpers
23 from tracker import tracker_bizobj
24 from tracker import tracker_constants
25 from tracker import tracker_helpers
26
27 TEST_ID_MAP = {
28 'a@example.com': 1,
29 'b@example.com': 2,
30 'c@example.com': 3,
31 'd@example.com': 4,
32 }
33
34
35 def _Issue(project_name, local_id, summary, status):
36 issue = tracker_pb2.Issue()
37 issue.project_name = project_name
38 issue.project_id = 789
39 issue.local_id = local_id
40 issue.issue_id = 100000 + local_id
41 issue.summary = summary
42 issue.status = status
43 return issue
44
45
46 def _MakeConfig():
47 config = tracker_pb2.ProjectIssueConfig()
48 config.well_known_statuses.append(tracker_pb2.StatusDef(
49 means_open=True, status='New', deprecated=False))
50 config.well_known_statuses.append(tracker_pb2.StatusDef(
51 status='Old', means_open=False, deprecated=False))
52 config.well_known_statuses.append(tracker_pb2.StatusDef(
53 status='StatusThatWeDontUseAnymore', means_open=False, deprecated=True))
54
55 return config
56
57
58 class HelpersTest(unittest.TestCase):
59
60 def setUp(self):
61 self.services = service_manager.Services(
62 project=fake.ProjectService(),
63 config=fake.ConfigService(),
64 issue=fake.IssueService(),
65 user=fake.UserService(),
66 usergroup=fake.UserGroupService())
67
68 for email, user_id in TEST_ID_MAP.iteritems():
69 self.services.user.TestAddUser(email, user_id)
70
71 self.services.project.TestAddProject('testproj', project_id=789)
72 self.issue1 = fake.MakeTestIssue(789, 1, 'one', 'New', 111L)
73 self.issue1.project_name = 'testproj'
74 self.services.issue.TestAddIssue(self.issue1)
75 self.issue2 = fake.MakeTestIssue(789, 2, 'two', 'New', 111L)
76 self.issue2.project_name = 'testproj'
77 self.services.issue.TestAddIssue(self.issue2)
78 self.issue3 = fake.MakeTestIssue(789, 3, 'three', 'New', 111L)
79 self.issue3.project_name = 'testproj'
80 self.services.issue.TestAddIssue(self.issue3)
81 self.cnxn = 'fake connextion'
82 self.errors = template_helpers.EZTError()
83 self.default_colspec_param = 'colspec=%s' % (
84 tracker_constants.DEFAULT_COL_SPEC.replace(' ', '%20'))
85 self.services.usergroup.TestAddGroupSettings(999L, 'group@example.com')
86
87 def testParseIssueRequest_Empty(self):
88 post_data = fake.PostData()
89 errors = template_helpers.EZTError()
90 parsed = tracker_helpers.ParseIssueRequest(
91 'fake cnxn', post_data, self.services, errors, 'proj')
92 self.assertEqual('', parsed.summary)
93 self.assertEqual('', parsed.comment)
94 self.assertEqual('', parsed.status)
95 self.assertEqual('', parsed.users.owner_username)
96 self.assertEqual(0, parsed.users.owner_id)
97 self.assertEqual([], parsed.users.cc_usernames)
98 self.assertEqual([], parsed.users.cc_usernames_remove)
99 self.assertEqual([], parsed.users.cc_ids)
100 self.assertEqual([], parsed.users.cc_ids_remove)
101 self.assertEqual('', parsed.template_name)
102 self.assertEqual([], parsed.labels)
103 self.assertEqual([], parsed.labels_remove)
104 self.assertEqual({}, parsed.fields.vals)
105 self.assertEqual({}, parsed.fields.vals_remove)
106 self.assertEqual([], parsed.fields.fields_clear)
107 self.assertEqual('', parsed.blocked_on.entered_str)
108 self.assertEqual([], parsed.blocked_on.iids)
109
110 def testParseIssueRequest_Normal(self):
111 post_data = fake.PostData({
112 'summary': ['some summary'],
113 'comment': ['some comment'],
114 'status': ['SomeStatus'],
115 'template_name': ['some template'],
116 'label': ['lab1', '-lab2'],
117 'custom_123': ['field1123a', 'field1123b'],
118 })
119 errors = template_helpers.EZTError()
120 parsed = tracker_helpers.ParseIssueRequest(
121 'fake cnxn', post_data, self.services, errors, 'proj')
122 self.assertEqual('some summary', parsed.summary)
123 self.assertEqual('some comment', parsed.comment)
124 self.assertEqual('SomeStatus', parsed.status)
125 self.assertEqual('', parsed.users.owner_username)
126 self.assertEqual(0, parsed.users.owner_id)
127 self.assertEqual([], parsed.users.cc_usernames)
128 self.assertEqual([], parsed.users.cc_usernames_remove)
129 self.assertEqual([], parsed.users.cc_ids)
130 self.assertEqual([], parsed.users.cc_ids_remove)
131 self.assertEqual('some template', parsed.template_name)
132 self.assertEqual(['lab1'], parsed.labels)
133 self.assertEqual(['lab2'], parsed.labels_remove)
134 self.assertEqual({123: ['field1123a', 'field1123b']}, parsed.fields.vals)
135 self.assertEqual({}, parsed.fields.vals_remove)
136 self.assertEqual([], parsed.fields.fields_clear)
137
138 def testParseBlockers_BlockedOnNothing(self):
139 """Was blocked on nothing, still nothing."""
140 post_data = {tracker_helpers.BLOCKED_ON: ''}
141 parsed_blockers = tracker_helpers._ParseBlockers(
142 self.cnxn, post_data, self.services, self.errors, 'testproj',
143 tracker_helpers.BLOCKED_ON)
144
145 self.assertEqual('', parsed_blockers.entered_str)
146 self.assertEqual([], parsed_blockers.iids)
147 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
148 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
149
150 def testParseBlockers_BlockedOnAdded(self):
151 """Was blocked on nothing; now 1, 2, 3."""
152 post_data = {tracker_helpers.BLOCKED_ON: '1, 2, 3'}
153 parsed_blockers = tracker_helpers._ParseBlockers(
154 self.cnxn, post_data, self.services, self.errors, 'testproj',
155 tracker_helpers.BLOCKED_ON)
156
157 self.assertEqual('1, 2, 3', parsed_blockers.entered_str)
158 self.assertEqual([100001, 100002, 100003], parsed_blockers.iids)
159 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
160 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
161
162 def testParseBlockers_BlockedOnDuplicateRef(self):
163 """Was blocked on nothing; now just 2, but repeated in input."""
164 post_data = {tracker_helpers.BLOCKED_ON: '2, 2, 2'}
165 parsed_blockers = tracker_helpers._ParseBlockers(
166 self.cnxn, post_data, self.services, self.errors, 'testproj',
167 tracker_helpers.BLOCKED_ON)
168
169 self.assertEqual('2, 2, 2', parsed_blockers.entered_str)
170 self.assertEqual([100002], parsed_blockers.iids)
171 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
172 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
173
174 def testParseBlockers_Missing(self):
175 """Parsing an input field that was not in the POST."""
176 post_data = {}
177 parsed_blockers = tracker_helpers._ParseBlockers(
178 self.cnxn, post_data, self.services, self.errors, 'testproj',
179 tracker_helpers.BLOCKED_ON)
180
181 self.assertEqual('', parsed_blockers.entered_str)
182 self.assertEqual([], parsed_blockers.iids)
183 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
184 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
185
186 def testParseBlockers_SameIssueNoProject(self):
187 """Adding same issue as blocker should modify the errors object."""
188 post_data = {'id': '2', tracker_helpers.BLOCKING: '2, 3'}
189
190 parsed_blockers = tracker_helpers._ParseBlockers(
191 self.cnxn, post_data, self.services, self.errors, 'testproj',
192 tracker_helpers.BLOCKING)
193 self.assertEqual('2, 3', parsed_blockers.entered_str)
194 self.assertEqual([], parsed_blockers.iids)
195 self.assertEqual(
196 getattr(self.errors, tracker_helpers.BLOCKING),
197 'Cannot be blocking the same issue')
198 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
199
200 def testParseBlockers_SameIssueSameProject(self):
201 """Adding same issue as blocker should modify the errors object."""
202 post_data = {'id': '2', tracker_helpers.BLOCKING: 'testproj:2, 3'}
203
204 parsed_blockers = tracker_helpers._ParseBlockers(
205 self.cnxn, post_data, self.services, self.errors, 'testproj',
206 tracker_helpers.BLOCKING)
207 self.assertEqual('testproj:2, 3', parsed_blockers.entered_str)
208 self.assertEqual([], parsed_blockers.iids)
209 self.assertEqual(
210 getattr(self.errors, tracker_helpers.BLOCKING),
211 'Cannot be blocking the same issue')
212 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
213
214 def testParseBlockers_SameIssueDifferentProject(self):
215 """Adding different blocker issue should not modify the errors object."""
216 post_data = {'id': '2', tracker_helpers.BLOCKING: 'testproj:2'}
217
218 parsed_blockers = tracker_helpers._ParseBlockers(
219 self.cnxn, post_data, self.services, self.errors, 'testprojB',
220 tracker_helpers.BLOCKING)
221 self.assertEqual('testproj:2', parsed_blockers.entered_str)
222 self.assertEqual([100002], parsed_blockers.iids)
223 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKING))
224 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
225
226 def testParseBlockers_Invalid(self):
227 """Input fields with invalid values should modify the errors object."""
228 post_data = {tracker_helpers.BLOCKING: '2, foo',
229 tracker_helpers.BLOCKED_ON: '3, bar'}
230
231 parsed_blockers = tracker_helpers._ParseBlockers(
232 self.cnxn, post_data, self.services, self.errors, 'testproj',
233 tracker_helpers.BLOCKING)
234 self.assertEqual('2, foo', parsed_blockers.entered_str)
235 self.assertEqual([100002], parsed_blockers.iids)
236 self.assertEqual(
237 getattr(self.errors, tracker_helpers.BLOCKING), 'Invalid issue ID foo')
238 self.assertIsNone(getattr(self.errors, tracker_helpers.BLOCKED_ON))
239
240 parsed_blockers = tracker_helpers._ParseBlockers(
241 self.cnxn, post_data, self.services, self.errors, 'testproj',
242 tracker_helpers.BLOCKED_ON)
243 self.assertEqual('3, bar', parsed_blockers.entered_str)
244 self.assertEqual([100003], parsed_blockers.iids)
245 self.assertEqual(
246 getattr(self.errors, tracker_helpers.BLOCKED_ON),
247 'Invalid issue ID bar')
248
249 def testParseBlockers_Dangling(self):
250 """A ref to a sanctioned projected should be allowed."""
251 post_data = {'id': '2', tracker_helpers.BLOCKING: 'otherproj:2'}
252 real_codesite_projects = settings.recognized_codesite_projects
253 settings.recognized_codesite_projects = ['otherproj']
254 parsed_blockers = tracker_helpers._ParseBlockers(
255 self.cnxn, post_data, self.services, self.errors, 'testproj',
256 tracker_helpers.BLOCKING)
257 self.assertEqual('otherproj:2', parsed_blockers.entered_str)
258 self.assertEqual([('otherproj', 2)], parsed_blockers.dangling_refs)
259 settings.recognized_codesite_projects = real_codesite_projects
260
261 def testMeansOpenInProject(self):
262 config = _MakeConfig()
263
264 # ensure open means open
265 self.assertTrue(tracker_helpers.MeansOpenInProject('New', config))
266 self.assertTrue(tracker_helpers.MeansOpenInProject('new', config))
267
268 # ensure an unrecognized status means open
269 self.assertTrue(tracker_helpers.MeansOpenInProject(
270 '_undefined_status_', config))
271
272 # ensure closed means closed
273 self.assertFalse(tracker_helpers.MeansOpenInProject('Old', config))
274 self.assertFalse(tracker_helpers.MeansOpenInProject('old', config))
275 self.assertFalse(tracker_helpers.MeansOpenInProject(
276 'StatusThatWeDontUseAnymore', config))
277
278 def testIsNoisy(self):
279 self.assertTrue(tracker_helpers.IsNoisy(778, 320))
280 self.assertFalse(tracker_helpers.IsNoisy(20, 500))
281 self.assertFalse(tracker_helpers.IsNoisy(500, 20))
282 self.assertFalse(tracker_helpers.IsNoisy(1, 1))
283
284 def testClassifyPlusMinusItems(self):
285 add, remove = tracker_helpers._ClassifyPlusMinusItems([])
286 self.assertEquals([], add)
287 self.assertEquals([], remove)
288
289 add, remove = tracker_helpers._ClassifyPlusMinusItems(
290 ['', ' ', ' \t', '-'])
291 self.assertItemsEqual([], add)
292 self.assertItemsEqual([], remove)
293
294 add, remove = tracker_helpers._ClassifyPlusMinusItems(
295 ['a', 'b', 'c'])
296 self.assertItemsEqual(['a', 'b', 'c'], add)
297 self.assertItemsEqual([], remove)
298
299 add, remove = tracker_helpers._ClassifyPlusMinusItems(
300 ['a-a-a', 'b-b', 'c-'])
301 self.assertItemsEqual(['a-a-a', 'b-b', 'c-'], add)
302 self.assertItemsEqual([], remove)
303
304 add, remove = tracker_helpers._ClassifyPlusMinusItems(
305 ['-a'])
306 self.assertItemsEqual([], add)
307 self.assertItemsEqual(['a'], remove)
308
309 add, remove = tracker_helpers._ClassifyPlusMinusItems(
310 ['-a', 'b', 'c-c'])
311 self.assertItemsEqual(['b', 'c-c'], add)
312 self.assertItemsEqual(['a'], remove)
313
314 add, remove = tracker_helpers._ClassifyPlusMinusItems(
315 ['-a', '-b-b', '-c-'])
316 self.assertItemsEqual([], add)
317 self.assertItemsEqual(['a', 'b-b', 'c-'], remove)
318
319 # We dedup, but we don't cancel out items that are both added and removed.
320 add, remove = tracker_helpers._ClassifyPlusMinusItems(
321 ['a', 'a', '-a'])
322 self.assertItemsEqual(['a'], add)
323 self.assertItemsEqual(['a'], remove)
324
325 def testParseIssueRequestAttachments(self):
326 file1 = testing_helpers.Blank(
327 filename='hello.c',
328 value='hello world')
329
330 file2 = testing_helpers.Blank(
331 filename='README',
332 value='Welcome to our project')
333
334 file3 = testing_helpers.Blank(
335 filename='c:\\dir\\subdir\\FILENAME.EXT',
336 value='Abort, Retry, or Fail?')
337
338 # Browsers send this if FILE field was not filled in.
339 file4 = testing_helpers.Blank(
340 filename='',
341 value='')
342
343 attachments = tracker_helpers._ParseIssueRequestAttachments({})
344 self.assertEquals([], attachments)
345
346 attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
347 'file1': [file1],
348 }))
349 self.assertEquals(
350 [('hello.c', 'hello world', 'text/plain')],
351 attachments)
352
353 attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
354 'file1': [file1],
355 'file2': [file2],
356 }))
357 self.assertEquals(
358 [('hello.c', 'hello world', 'text/plain'),
359 ('README', 'Welcome to our project', 'text/plain')],
360 attachments)
361
362 attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
363 'file3': [file3],
364 }))
365 self.assertEquals(
366 [('FILENAME.EXT', 'Abort, Retry, or Fail?',
367 'application/octet-stream')],
368 attachments)
369
370 attachments = tracker_helpers._ParseIssueRequestAttachments(fake.PostData({
371 'file1': [file4], # Does not appear in result
372 'file3': [file3],
373 'file4': [file4], # Does not appear in result
374 }))
375 self.assertEquals(
376 [('FILENAME.EXT', 'Abort, Retry, or Fail?',
377 'application/octet-stream')],
378 attachments)
379
380 def testParseIssueRequestUsers(self):
381 post_data = {}
382 parsed_users = tracker_helpers._ParseIssueRequestUsers(
383 'fake connection', post_data, self.services)
384 self.assertEquals('', parsed_users.owner_username)
385 self.assertEquals(
386 framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
387 self.assertEquals([], parsed_users.cc_usernames)
388 self.assertEquals([], parsed_users.cc_usernames_remove)
389 self.assertEquals([], parsed_users.cc_ids)
390 self.assertEquals([], parsed_users.cc_ids_remove)
391
392 post_data = fake.PostData({
393 'owner': [''],
394 })
395 parsed_users = tracker_helpers._ParseIssueRequestUsers(
396 'fake connection', post_data, self.services)
397 self.assertEquals('', parsed_users.owner_username)
398 self.assertEquals(
399 framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
400 self.assertEquals([], parsed_users.cc_usernames)
401 self.assertEquals([], parsed_users.cc_usernames_remove)
402 self.assertEquals([], parsed_users.cc_ids)
403 self.assertEquals([], parsed_users.cc_ids_remove)
404
405 post_data = fake.PostData({
406 'owner': [' \t'],
407 })
408 parsed_users = tracker_helpers._ParseIssueRequestUsers(
409 'fake connection', post_data, self.services)
410 self.assertEquals('', parsed_users.owner_username)
411 self.assertEquals(
412 framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
413 self.assertEquals([], parsed_users.cc_usernames)
414 self.assertEquals([], parsed_users.cc_usernames_remove)
415 self.assertEquals([], parsed_users.cc_ids)
416 self.assertEquals([], parsed_users.cc_ids_remove)
417
418 post_data = fake.PostData({
419 'owner': ['b@example.com'],
420 })
421 parsed_users = tracker_helpers._ParseIssueRequestUsers(
422 'fake connection', post_data, self.services)
423 self.assertEquals('b@example.com', parsed_users.owner_username)
424 self.assertEquals(TEST_ID_MAP['b@example.com'], parsed_users.owner_id)
425 self.assertEquals([], parsed_users.cc_usernames)
426 self.assertEquals([], parsed_users.cc_usernames_remove)
427 self.assertEquals([], parsed_users.cc_ids)
428 self.assertEquals([], parsed_users.cc_ids_remove)
429
430 post_data = fake.PostData({
431 'owner': ['b@example.com'],
432 })
433 parsed_users = tracker_helpers._ParseIssueRequestUsers(
434 'fake connection', post_data, self.services)
435 self.assertEquals('b@example.com', parsed_users.owner_username)
436 self.assertEquals(TEST_ID_MAP['b@example.com'], parsed_users.owner_id)
437 self.assertEquals([], parsed_users.cc_usernames)
438 self.assertEquals([], parsed_users.cc_usernames_remove)
439 self.assertEquals([], parsed_users.cc_ids)
440 self.assertEquals([], parsed_users.cc_ids_remove)
441
442 post_data = fake.PostData({
443 'cc': ['b@example.com'],
444 })
445 parsed_users = tracker_helpers._ParseIssueRequestUsers(
446 'fake connection', post_data, self.services)
447 self.assertEquals('', parsed_users.owner_username)
448 self.assertEquals(
449 framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
450 self.assertEquals(['b@example.com'], parsed_users.cc_usernames)
451 self.assertEquals([], parsed_users.cc_usernames_remove)
452 self.assertEquals([TEST_ID_MAP['b@example.com']], parsed_users.cc_ids)
453 self.assertEquals([], parsed_users.cc_ids_remove)
454
455 post_data = fake.PostData({
456 'cc': ['-b@example.com, c@example.com,,'
457 'a@example.com,'],
458 })
459 parsed_users = tracker_helpers._ParseIssueRequestUsers(
460 'fake connection', post_data, self.services)
461 self.assertEquals('', parsed_users.owner_username)
462 self.assertEquals(
463 framework_constants.NO_USER_SPECIFIED, parsed_users.owner_id)
464 self.assertItemsEqual(['c@example.com', 'a@example.com'],
465 parsed_users.cc_usernames)
466 self.assertEquals(['b@example.com'], parsed_users.cc_usernames_remove)
467 self.assertItemsEqual([TEST_ID_MAP['c@example.com'],
468 TEST_ID_MAP['a@example.com']],
469 parsed_users.cc_ids)
470 self.assertEquals([TEST_ID_MAP['b@example.com']],
471 parsed_users.cc_ids_remove)
472
473 post_data = fake.PostData({
474 'owner': ['fuhqwhgads@example.com'],
475 'cc': ['c@example.com, fuhqwhgads@example.com'],
476 })
477 parsed_users = tracker_helpers._ParseIssueRequestUsers(
478 'fake connection', post_data, self.services)
479 self.assertEquals('fuhqwhgads@example.com', parsed_users.owner_username)
480 gen_uid = framework_helpers.MurmurHash3_x86_32(parsed_users.owner_username)
481 self.assertEquals(gen_uid, parsed_users.owner_id) # autocreated user
482 self.assertItemsEqual(
483 ['c@example.com', 'fuhqwhgads@example.com'], parsed_users.cc_usernames)
484 self.assertEquals([], parsed_users.cc_usernames_remove)
485 self.assertItemsEqual(
486 [TEST_ID_MAP['c@example.com'], gen_uid], parsed_users.cc_ids)
487 self.assertEquals([], parsed_users.cc_ids_remove)
488
489 def testIsValidIssueOwner(self):
490 project = project_pb2.Project()
491 project.owner_ids.extend([1L, 2L])
492 project.committer_ids.extend([3L])
493 project.contributor_ids.extend([4L, 999L])
494
495 valid, _ = tracker_helpers.IsValidIssueOwner(
496 'fake cnxn', project, framework_constants.NO_USER_SPECIFIED,
497 self.services)
498 self.assertTrue(valid)
499
500 valid, _ = tracker_helpers.IsValidIssueOwner(
501 'fake cnxn', project, 1L,
502 self.services)
503 self.assertTrue(valid)
504 valid, _ = tracker_helpers.IsValidIssueOwner(
505 'fake cnxn', project, 2L,
506 self.services)
507 self.assertTrue(valid)
508 valid, _ = tracker_helpers.IsValidIssueOwner(
509 'fake cnxn', project, 3L,
510 self.services)
511 self.assertTrue(valid)
512 valid, _ = tracker_helpers.IsValidIssueOwner(
513 'fake cnxn', project, 4L,
514 self.services)
515 self.assertTrue(valid)
516
517 valid, _ = tracker_helpers.IsValidIssueOwner(
518 'fake cnxn', project, 7L,
519 self.services)
520 self.assertFalse(valid)
521
522 valid, _ = tracker_helpers.IsValidIssueOwner(
523 'fake cnxn', project, 999L,
524 self.services)
525 self.assertFalse(valid)
526
527 def testGetAllowedOpenAndClosedRelatedIssues(self):
528 gaoacri = tracker_helpers.GetAllowedOpenAndClosedRelatedIssues
529 opened = {
530 100001: _Issue('proj', 1, 'summary 1', 'New'),
531 100002: _Issue('proj', 2, 'summary 2', 'Accepted'),
532 }
533 closed = {
534 100003: _Issue('proj', 3, 'summary 3', 'Accepted'),
535 100004: _Issue('proj', 4, 'summary 4', 'Invalid'),
536 }
537 project = project_pb2.Project()
538 project.project_id = 789
539 project.project_name = 'proj'
540 project.state = project_pb2.ProjectState.LIVE
541 mr = testing_helpers.MakeMonorailRequest(project=project)
542 fake_issue_service = testing_helpers.Blank(
543 GetOpenAndClosedIssues=lambda _cnxn, iids: (
544 [opened[iid] for iid in iids if iid in opened],
545 [closed[iid] for iid in iids if iid in closed]))
546 fake_config_service = testing_helpers.Blank(
547 GetProjectConfigs=lambda _cnxn, pids: (
548 {pid: tracker_bizobj.MakeDefaultProjectIssueConfig(pid)
549 for pid in pids}))
550 fake_project_service = testing_helpers.Blank(
551 GetProjects=lambda _, project_ids: {project.project_id: project})
552 services = service_manager.Services(
553 issue=fake_issue_service, config=fake_config_service,
554 project=fake_project_service)
555
556 issue = tracker_pb2.Issue()
557 issue.project_id = 789
558 # No merged into, no blocking, no blocked on.
559 open_dict, closed_dict = gaoacri(services, mr, issue)
560 self.assertEqual({}, open_dict)
561 self.assertEqual({}, closed_dict)
562
563 # An open "merged into"
564 issue.merged_into = 100001
565 open_dict, closed_dict = gaoacri(services, mr, issue)
566 self.assertEqual({100001: opened[100001]}, open_dict)
567 self.assertEqual({}, closed_dict)
568
569 # A closed "merged into"
570 issue.merged_into = 100003
571 open_dict, closed_dict = gaoacri(services, mr, issue)
572 self.assertEqual({}, open_dict)
573 self.assertEqual({100003: closed[100003]}, closed_dict)
574
575 # Some blocking and blocked on
576 issue.blocking_iids.append(100001)
577 issue.blocked_on_iids.append(100004)
578 open_dict, closed_dict = gaoacri(services, mr, issue)
579 self.assertEqual({100001: opened[100001]}, open_dict)
580 self.assertEqual({100003: closed[100003],
581 100004: closed[100004]}, closed_dict)
582
583 def testMergeCCsAndAddComment(self):
584 target_issue = fake.MakeTestIssue(
585 789, 10, 'Target issue', 'New', 111L)
586 source_issue = fake.MakeTestIssue(
587 789, 100, 'Source issue', 'New', 222L)
588 source_issue.cc_ids.append(111L)
589 # Issue without owner
590 source_issue_2 = fake.MakeTestIssue(
591 789, 101, 'Source issue 2', 'New', 0L)
592
593 project = self.services.project.TestAddProject(
594 'testproj', owner_ids=[222L], project_id=789)
595 self.services.issue.TestAddIssue(target_issue)
596 self.services.issue.TestAddIssue(source_issue)
597 self.services.issue.TestAddIssue(source_issue_2)
598
599 # We copy this list so that it isn't updated by the test framework
600 initial_issue_comments = (
601 self.services.issue.GetCommentsForIssue(
602 'fake cnxn', target_issue.issue_id)[:])
603 mr = testing_helpers.MakeMonorailRequest(user_info={'user_id': 111L})
604
605 # Merging source into target should create a comment.
606 self.assertIsNotNone(
607 tracker_helpers.MergeCCsAndAddComment(
608 self.services, mr, source_issue, project, target_issue))
609 updated_issue_comments = self.services.issue.GetCommentsForIssue(
610 'fake cnxn', target_issue.issue_id)
611 for comment in initial_issue_comments:
612 self.assertIn(comment, updated_issue_comments)
613 self.assertEqual(
614 len(initial_issue_comments) + 1, len(updated_issue_comments))
615
616 # Merging source into target should add source's owner to target's CCs.
617 updated_target_issue = self.services.issue.GetIssueByLocalID(
618 'fake cnxn', 789, 10)
619 self.assertIn(111L, updated_target_issue.cc_ids)
620 self.assertIn(222L, updated_target_issue.cc_ids)
621
622 # Merging source 2 into target should make a comment, but not update CCs.
623 self.assertIsNotNone(
624 tracker_helpers.MergeCCsAndAddComment(
625 self.services, mr, source_issue_2, project, updated_target_issue))
626 updated_target_issue = self.services.issue.GetIssueByLocalID(
627 'fake cnxn', 789, 10)
628 self.assertNotIn(0L, updated_target_issue.cc_ids)
629
630 def testMergeCCsAndAddCommentRestrictedSourceIssue(self):
631 target_issue = fake.MakeTestIssue(
632 789, 10, 'Target issue', 'New', 222L)
633 target_issue_2 = fake.MakeTestIssue(
634 789, 11, 'Target issue 2', 'New', 222L)
635 source_issue = fake.MakeTestIssue(
636 789, 100, 'Source issue', 'New', 111L)
637 source_issue.cc_ids.append(111L)
638 source_issue.labels.append('Restrict-View-Commit')
639 target_issue_2.labels.append('Restrict-View-Commit')
640
641 project = self.services.project.TestAddProject(
642 'testproj', owner_ids=[222L], project_id=789)
643 self.services.issue.TestAddIssue(source_issue)
644 self.services.issue.TestAddIssue(target_issue)
645 self.services.issue.TestAddIssue(target_issue_2)
646
647 # We copy this list so that it isn't updated by the test framework
648 initial_issue_comments = self.services.issue.GetCommentsForIssue(
649 'fake cnxn', target_issue.issue_id)[:]
650 mr = testing_helpers.MakeMonorailRequest(user_info={'user_id': 111L})
651 self.assertIsNotNone(
652 tracker_helpers.MergeCCsAndAddComment(
653 self.services, mr, source_issue, project, target_issue))
654
655 # When the source is restricted, we update the target comments...
656 updated_issue_comments = self.services.issue.GetCommentsForIssue(
657 'fake cnxn', target_issue.issue_id)
658 for comment in initial_issue_comments:
659 self.assertIn(comment, updated_issue_comments)
660 self.assertEqual(
661 len(initial_issue_comments) + 1, len(updated_issue_comments))
662 # ...but not the target CCs...
663 updated_target_issue = self.services.issue.GetIssueByLocalID(
664 'fake cnxn', 789, 10)
665 self.assertNotIn(111L, updated_target_issue.cc_ids)
666 # ...unless both issues have the same restrictions.
667 self.assertIsNotNone(
668 tracker_helpers.MergeCCsAndAddComment(
669 self.services, mr, source_issue, project, target_issue_2))
670 updated_target_issue_2 = self.services.issue.GetIssueByLocalID(
671 'fake cnxn', 789, 11)
672 self.assertIn(111L, updated_target_issue_2.cc_ids)
673
674 def testFormatIssueListURLNoCurrentState(self):
675 config = tracker_pb2.ProjectIssueConfig()
676 path = '/p/proj/issues/detail?id=123'
677 mr = testing_helpers.MakeMonorailRequest(
678 path=path, headers={'Host': 'code.google.com'})
679 mr.ComputeColSpec(config)
680
681 absolute_base_url = 'http://code.google.com'
682
683 url_1 = tracker_helpers.FormatIssueListURL(mr, config)
684 self.assertEquals(
685 '%s/p/proj/issues/list?%s' % (
686 absolute_base_url, self.default_colspec_param),
687 url_1)
688
689 url_2 = tracker_helpers.FormatIssueListURL(
690 mr, config, foo=123)
691 self.assertEquals(
692 '%s/p/proj/issues/list?%s&foo=123' % (
693 absolute_base_url, self.default_colspec_param),
694 url_2)
695
696 url_3 = tracker_helpers.FormatIssueListURL(
697 mr, config, foo=123, bar='abc')
698 self.assertEquals(
699 '%s/p/proj/issues/list?bar=abc&%s&foo=123' % (
700 absolute_base_url, self.default_colspec_param),
701 url_3)
702
703 url_4 = tracker_helpers.FormatIssueListURL(
704 mr, config, baz='escaped+encoded&and100% "safe"')
705 self.assertEquals(
706 '%s/p/proj/issues/list?'
707 'baz=escaped%%2Bencoded%%26and100%%25%%20%%22safe%%22&%s' % (
708 absolute_base_url, self.default_colspec_param),
709 url_4)
710
711 def testFormatIssueListURLKeepCurrentState(self):
712 config = tracker_pb2.ProjectIssueConfig()
713 path = '/p/proj/issues/detail?id=123&sort=aa&colspec=a b c&groupby=d'
714 mr = testing_helpers.MakeMonorailRequest(
715 path=path, headers={'Host': 'localhost:8080'})
716 mr.ComputeColSpec(config)
717
718 absolute_base_url = 'http://localhost:8080'
719
720 url_1 = tracker_helpers.FormatIssueListURL(mr, config)
721 self.assertEquals(
722 '%s/p/proj/issues/list?colspec=a%%20b%%20c'
723 '&groupby=d&sort=aa' % absolute_base_url,
724 url_1)
725
726 url_2 = tracker_helpers.FormatIssueListURL(
727 mr, config, foo=123)
728 self.assertEquals(
729 '%s/p/proj/issues/list?'
730 'colspec=a%%20b%%20c&foo=123&groupby=d&sort=aa' % absolute_base_url,
731 url_2)
732
733 url_3 = tracker_helpers.FormatIssueListURL(
734 mr, config, colspec='X Y Z')
735 self.assertEquals(
736 '%s/p/proj/issues/list?colspec=a%%20b%%20c'
737 '&groupby=d&sort=aa' % absolute_base_url,
738 url_3)
739
740 def testFormatRelativeIssueURL(self):
741 self.assertEquals(
742 '/p/proj/issues/attachment',
743 tracker_helpers.FormatRelativeIssueURL(
744 'proj', urls.ISSUE_ATTACHMENT))
745
746 self.assertEquals(
747 '/p/proj/issues/detail?id=123',
748 tracker_helpers.FormatRelativeIssueURL(
749 'proj', urls.ISSUE_DETAIL, id=123))
750
751
752 class MakeViewsForUsersInIssuesTest(unittest.TestCase):
753
754 def setUp(self):
755 self.issue1 = _Issue('proj', 1, 'summary 1', 'New')
756 self.issue1.owner_id = 1001
757 self.issue1.reporter_id = 1002
758
759 self.issue2 = _Issue('proj', 2, 'summary 2', 'New')
760 self.issue2.owner_id = 2001
761 self.issue2.reporter_id = 2002
762 self.issue2.cc_ids.extend([1, 1001, 1002, 1003])
763
764 self.issue3 = _Issue('proj', 3, 'summary 3', 'New')
765 self.issue3.owner_id = 1001
766 self.issue3.reporter_id = 3002
767
768 self.user = fake.UserService()
769 for user_id in [1, 1001, 1002, 1003, 2001, 2002, 3002]:
770 self.user.TestAddUser(
771 'test%d' % user_id, user_id, add_user=True)
772
773 def testMakeViewsForUsersInIssues(self):
774 issue_list = [self.issue1, self.issue2, self.issue3]
775 users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
776 'fake cnxn', issue_list, self.user)
777 self.assertItemsEqual([1, 1001, 1002, 1003, 2001, 2002, 3002],
778 users_by_id.keys())
779 for user_id in [1001, 1002, 1003, 2001]:
780 self.assertEqual(users_by_id[user_id].user_id, user_id)
781
782 def testMakeViewsForUsersInIssuesOmittingSome(self):
783 issue_list = [self.issue1, self.issue2, self.issue3]
784 users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
785 'fake cnxn', issue_list, self.user, omit_ids=[1001, 1003])
786 self.assertItemsEqual([1, 1002, 2001, 2002, 3002], users_by_id.keys())
787 for user_id in [1002, 2001, 2002, 3002]:
788 self.assertEqual(users_by_id[user_id].user_id, user_id)
789
790 def testMakeViewsForUsersInIssuesEmpty(self):
791 issue_list = []
792 users_by_id = tracker_helpers.MakeViewsForUsersInIssues(
793 'fake cnxn', issue_list, self.user)
794 self.assertItemsEqual([], users_by_id.keys())
795
796
797 class GetAllIssueProjectsTest(unittest.TestCase):
798 issue_x_1 = tracker_pb2.Issue()
799 issue_x_1.project_id = 789
800 issue_x_1.local_id = 1
801 issue_x_1.reporter_id = 1002
802
803 issue_x_2 = tracker_pb2.Issue()
804 issue_x_2.project_id = 789
805 issue_x_2.local_id = 2
806 issue_x_2.reporter_id = 2002
807
808 issue_y_1 = tracker_pb2.Issue()
809 issue_y_1.project_id = 678
810 issue_y_1.local_id = 1
811 issue_y_1.reporter_id = 2002
812
813 def setUp(self):
814 self.project_service = fake.ProjectService()
815 self.project_service.TestAddProject('proj-x', project_id=789)
816 self.project_service.TestAddProject('proj-y', project_id=678)
817 self.cnxn = 'fake connection'
818
819 def testGetAllIssueProjects_Empty(self):
820 self.assertEqual(
821 {}, tracker_helpers.GetAllIssueProjects(
822 self.cnxn, [], self.project_service))
823
824 def testGetAllIssueProjects_Normal(self):
825 self.assertEqual(
826 {789: self.project_service.GetProjectByName(self.cnxn, 'proj-x')},
827 tracker_helpers.GetAllIssueProjects(
828 self.cnxn, [self.issue_x_1, self.issue_x_2], self.project_service))
829 self.assertEqual(
830 {789: self.project_service.GetProjectByName(self.cnxn, 'proj-x'),
831 678: self.project_service.GetProjectByName(self.cnxn, 'proj-y')},
832 tracker_helpers.GetAllIssueProjects(
833 self.cnxn, [self.issue_x_1, self.issue_x_2, self.issue_y_1],
834 self.project_service))
835
836
837 class FilterOutNonViewableIssuesTest(unittest.TestCase):
838 owner_id = 111L
839 committer_id = 222L
840 nonmember_1_id = 1002L
841 nonmember_2_id = 2002L
842 nonmember_3_id = 3002L
843
844 issue1 = tracker_pb2.Issue()
845 issue1.project_name = 'proj'
846 issue1.project_id = 789
847 issue1.local_id = 1
848 issue1.reporter_id = nonmember_1_id
849
850 issue2 = tracker_pb2.Issue()
851 issue2.project_name = 'proj'
852 issue2.project_id = 789
853 issue2.local_id = 2
854 issue2.reporter_id = nonmember_2_id
855 issue2.labels.extend(['foo', 'bar'])
856
857 issue3 = tracker_pb2.Issue()
858 issue3.project_name = 'proj'
859 issue3.project_id = 789
860 issue3.local_id = 3
861 issue3.reporter_id = nonmember_3_id
862 issue3.labels.extend(['restrict-view-commit'])
863
864 issue4 = tracker_pb2.Issue()
865 issue4.project_name = 'proj'
866 issue4.project_id = 789
867 issue4.local_id = 4
868 issue4.reporter_id = nonmember_3_id
869 issue4.labels.extend(['Foo', 'Restrict-View-Commit'])
870
871 def setUp(self):
872 self.user = user_pb2.User()
873 self.project = self.MakeProject(project_pb2.ProjectState.LIVE)
874 self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(
875 self.project.project_id)
876 self.project_dict = {self.project.project_id: self.project}
877 self.config_dict = {self.config.project_id: self.config}
878
879 def MakeProject(self, state):
880 p = project_pb2.Project(
881 project_id=789, project_name='proj', state=state,
882 owner_ids=[self.owner_id], committer_ids=[self.committer_id])
883 return p
884
885 def testFilterOutNonViewableIssues_Member(self):
886 # perms will be permissions.COMMITTER_ACTIVE_PERMISSIONSET
887 filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
888 {self.committer_id}, self.user, self.project_dict,
889 self.config_dict,
890 [self.issue1, self.issue2, self.issue3, self.issue4])
891 self.assertListEqual([1, 2, 3, 4],
892 [issue.local_id for issue in filtered_issues])
893
894 def testFilterOutNonViewableIssues_Owner(self):
895 # perms will be permissions.OWNER_ACTIVE_PERMISSIONSET
896 filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
897 {self.owner_id}, self.user, self.project_dict, self.config_dict,
898 [self.issue1, self.issue2, self.issue3, self.issue4])
899 self.assertListEqual([1, 2, 3, 4],
900 [issue.local_id for issue in filtered_issues])
901
902 def testFilterOutNonViewableIssues_Empty(self):
903 # perms will be permissions.COMMITTER_ACTIVE_PERMISSIONSET
904 filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
905 {self.committer_id}, self.user, self.project_dict,
906 self.config_dict, [])
907 self.assertListEqual([], filtered_issues)
908
909 def testFilterOutNonViewableIssues_NonMember(self):
910 # perms will be permissions.READ_ONLY_PERMISSIONSET
911 filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
912 {self.nonmember_1_id}, self.user, self.project_dict,
913 self.config_dict, [self.issue1, self.issue2, self.issue3, self.issue4])
914 self.assertListEqual([1, 2],
915 [issue.local_id for issue in filtered_issues])
916
917 def testFilterOutNonViewableIssues_Reporter(self):
918 # perms will be permissions.READ_ONLY_PERMISSIONSET
919 filtered_issues = tracker_helpers.FilterOutNonViewableIssues(
920 {self.nonmember_3_id}, self.user, self.project_dict,
921 self.config_dict, [self.issue1, self.issue2, self.issue3, self.issue4])
922 self.assertListEqual([1, 2, 3, 4],
923 [issue.local_id for issue in filtered_issues])
924
925
926 class IssueMergeTest(unittest.TestCase):
927
928 def setUp(self):
929 self.cnxn = 'fake cnxn'
930 self.services = service_manager.Services(
931 config=fake.ConfigService(),
932 issue=fake.IssueService(),
933 user=fake.UserService(),
934 project=fake.ProjectService(),
935 issue_star=fake.IssueStarService(),
936 spam=fake.SpamService()
937 )
938 self.project = self.services.project.TestAddProject('proj', project_id=987)
939 self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(
940 self.project.project_id)
941 self.project_dict = {self.project.project_id: self.project}
942 self.config_dict = {self.config.project_id: self.config}
943
944 def testParseMergeFields_NotSpecified(self):
945 issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
946 errors = template_helpers.EZTError()
947 post_data = {}
948
949 text, merge_into_issue = tracker_helpers.ParseMergeFields(
950 self.cnxn, None, 'proj', post_data, 'New', self.config, issue, errors)
951 self.assertEqual('', text)
952 self.assertEqual(None, merge_into_issue)
953
954 text, merge_into_issue = tracker_helpers.ParseMergeFields(
955 self.cnxn, None, 'proj', post_data, 'Duplicate', self.config, issue,
956 errors)
957 self.assertEqual('', text)
958 self.assertTrue(errors.merge_into_id)
959 self.assertEqual(None, merge_into_issue)
960
961 def testParseMergeFields_WrongStatus(self):
962 issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
963 errors = template_helpers.EZTError()
964 post_data = {'merge_into': '12'}
965
966 text, merge_into_issue = tracker_helpers.ParseMergeFields(
967 self.cnxn, None, 'proj', post_data, 'New', self.config, issue, errors)
968 self.assertEqual('', text)
969 self.assertEqual(None, merge_into_issue)
970
971 def testParseMergeFields_NoSuchIssue(self):
972 issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
973 issue.merged_into = 12
974 errors = template_helpers.EZTError()
975 post_data = {'merge_into': '12'}
976
977 text, merge_into_issue = tracker_helpers.ParseMergeFields(
978 self.cnxn, self.services, 'proj', post_data, 'Duplicate',
979 self.config, issue, errors)
980 self.assertEqual('12', text)
981 self.assertEqual(None, merge_into_issue)
982
983 def testParseMergeFields_DontSelfMerge(self):
984 issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
985 errors = template_helpers.EZTError()
986 post_data = {'merge_into': '1'}
987
988 text, merge_into_issue = tracker_helpers.ParseMergeFields(
989 self.cnxn, self.services, 'proj', post_data, 'Duplicate', self.config,
990 issue, errors)
991 self.assertEqual('1', text)
992 self.assertEqual(None, merge_into_issue)
993 self.assertEqual('Cannot merge issue into itself', errors.merge_into_id)
994
995 def testParseMergeFields_NewIssueToMerge(self):
996 merged_local_id = self.services.issue.CreateIssue(
997 self.cnxn, self.services,
998 self.project.project_id, 'unused_summary', 'unused_status', 111L,
999 [], [], [], [], 111L, 'unused_marked_description')
1000 mergee_local_id = self.services.issue.CreateIssue(
1001 self.cnxn, self.services,
1002 self.project.project_id, 'unused_summary', 'unused_status', 111L,
1003 [], [], [], [], 111L, 'unused_marked_description')
1004 merged_issue = self.services.issue.GetIssueByLocalID(
1005 self.cnxn, self.project.project_id, merged_local_id)
1006 mergee_issue = self.services.issue.GetIssueByLocalID(
1007 self.cnxn, self.project.project_id, mergee_local_id)
1008
1009 errors = template_helpers.EZTError()
1010 post_data = {'merge_into': str(mergee_issue.local_id)}
1011
1012 text, merge_into_issue = tracker_helpers.ParseMergeFields(
1013 self.cnxn, self.services, 'proj', post_data, 'Duplicate', self.config,
1014 merged_issue, errors)
1015 self.assertEqual(str(mergee_issue.local_id), text)
1016 self.assertEqual(mergee_issue, merge_into_issue)
1017
1018 def testIsMergeAllowed(self):
1019 mr = testing_helpers.MakeMonorailRequest()
1020 issue = fake.MakeTestIssue(987, 1, 'summary', 'New', 111L)
1021 issue.project_name = self.project.project_name
1022
1023 for (perm_set, expected_merge_allowed) in (
1024 (permissions.READ_ONLY_PERMISSIONSET, False),
1025 (permissions.COMMITTER_INACTIVE_PERMISSIONSET, False),
1026 (permissions.COMMITTER_ACTIVE_PERMISSIONSET, True),
1027 (permissions.OWNER_ACTIVE_PERMISSIONSET, True)):
1028 mr.perms = perm_set
1029 merge_allowed = tracker_helpers.IsMergeAllowed(issue, mr, self.services)
1030 self.assertEquals(expected_merge_allowed, merge_allowed)
1031
1032 def testMergeIssueStars(self):
1033 mr = testing_helpers.MakeMonorailRequest()
1034 mr.project_name = self.project.project_name
1035 mr.project = self.project
1036
1037 config = self.services.config.GetProjectConfig(
1038 self.cnxn, self.project.project_id)
1039 self.services.issue_star.SetStar(
1040 self.cnxn, self.services, config, 1, 1, True)
1041 self.services.issue_star.SetStar(
1042 self.cnxn, self.services, config, 1, 2, True)
1043 self.services.issue_star.SetStar(
1044 self.cnxn, self.services, config, 1, 3, True)
1045 self.services.issue_star.SetStar(
1046 self.cnxn, self.services, config, 2, 3, True)
1047 self.services.issue_star.SetStar(
1048 self.cnxn, self.services, config, 2, 4, True)
1049 self.services.issue_star.SetStar(
1050 self.cnxn, self.services, config, 2, 5, True)
1051
1052 new_starrers = tracker_helpers.GetNewIssueStarrers(
1053 self.cnxn, self.services, 1, 2)
1054 self.assertItemsEqual(new_starrers, [1, 2])
1055 tracker_helpers.AddIssueStarrers(
1056 self.cnxn, self.services, mr, 2, self.project, new_starrers)
1057 issue_2_starrers = self.services.issue_star.LookupItemStarrers(
1058 self.cnxn, 2)
1059 # XXX(jrobbins): these tests incorrectly mix local IDs with IIDs.
1060 self.assertItemsEqual([1, 2, 3, 4, 5], issue_2_starrers)
1061
1062
1063 if __name__ == '__main__':
1064 unittest.main()
OLDNEW
« 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