blob: 29351b030a87caf3142c9b78873cb2e95e5d865c [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed 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"""Tests for issue bizobj functions."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import unittest
12import logging
13
14from framework import framework_constants
15from framework import framework_views
16from proto import tracker_pb2
17from services import service_manager
18from testing import fake
19from testing import testing_helpers
20from tracker import tracker_bizobj
21from tracker import tracker_constants
22
23
24class BizobjTest(unittest.TestCase):
25
26 def setUp(self):
27 self.cnxn = 'fake cnxn'
28 self.services = service_manager.Services(
29 issue=fake.IssueService())
30 self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
31 self.config.field_defs = [
32 tracker_pb2.FieldDef(
33 field_id=1, project_id=789, field_name='EstDays',
34 field_type=tracker_pb2.FieldTypes.INT_TYPE)
35 ]
36 self.config.component_defs = [
37 tracker_pb2.ComponentDef(component_id=1, project_id=789, path='UI'),
38 tracker_pb2.ComponentDef(component_id=2, project_id=789, path='DB'),
39 ]
40
41 def testGetOwnerId(self):
42 issue = tracker_pb2.Issue()
43 self.assertEqual(
44 tracker_bizobj.GetOwnerId(issue), framework_constants.NO_USER_SPECIFIED)
45
46 issue.derived_owner_id = 123
47 self.assertEqual(tracker_bizobj.GetOwnerId(issue), 123)
48
49 issue.owner_id = 456
50 self.assertEqual(tracker_bizobj.GetOwnerId(issue), 456)
51
52 def testGetStatus(self):
53 issue = tracker_pb2.Issue()
54 self.assertEqual(tracker_bizobj.GetStatus(issue), '')
55
56 issue.derived_status = 'InReview'
57 self.assertEqual(tracker_bizobj.GetStatus(issue), 'InReview')
58
59 issue.status = 'Forgotten'
60 self.assertEqual(tracker_bizobj.GetStatus(issue), 'Forgotten')
61
62 def testGetCcIds(self):
63 issue = tracker_pb2.Issue()
64 self.assertEqual(tracker_bizobj.GetCcIds(issue), [])
65
66 issue.derived_cc_ids.extend([1, 2, 3])
67 self.assertEqual(tracker_bizobj.GetCcIds(issue), [1, 2, 3])
68
69 issue.cc_ids.extend([4, 5, 6])
70 self.assertEqual(tracker_bizobj.GetCcIds(issue), [4, 5, 6, 1, 2, 3])
71
72 def testGetApproverIds(self):
73 issue = tracker_pb2.Issue()
74 self.assertEqual(tracker_bizobj.GetApproverIds(issue), [])
75
76 av_1 = tracker_pb2.ApprovalValue(approver_ids=[111, 222])
77 av_2 = tracker_pb2.ApprovalValue()
78 av_3 = tracker_pb2.ApprovalValue(approver_ids=[222, 333])
79 issue.approval_values = [av_1, av_2, av_3]
80 self.assertItemsEqual(
81 tracker_bizobj.GetApproverIds(issue), [111, 222, 333])
82
83 def testGetLabels(self):
84 issue = tracker_pb2.Issue()
85 self.assertEqual(tracker_bizobj.GetLabels(issue), [])
86
87 issue.derived_labels.extend(['a', 'b', 'c'])
88 self.assertEqual(tracker_bizobj.GetLabels(issue), ['a', 'b', 'c'])
89
90 issue.labels.extend(['d', 'e', 'f'])
91 self.assertEqual(
92 tracker_bizobj.GetLabels(issue), ['d', 'e', 'f', 'a', 'b', 'c'])
93
94 def testFindFieldDef_None(self):
95 config = tracker_pb2.ProjectIssueConfig()
96 self.assertIsNone(tracker_bizobj.FindFieldDef(None, config))
97
98 def testFindFieldDef_Empty(self):
99 config = tracker_pb2.ProjectIssueConfig()
100 self.assertIsNone(tracker_bizobj.FindFieldDef('EstDays', config))
101
102 def testFindFieldDef_Default(self):
103 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
104 self.assertIsNone(tracker_bizobj.FindFieldDef('EstDays', config))
105
106 def testFindFieldDef_Normal(self):
107 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
108 fd = tracker_pb2.FieldDef(field_name='EstDays')
109 config.field_defs = [fd]
110 self.assertEqual(fd, tracker_bizobj.FindFieldDef('EstDays', config))
111 self.assertEqual(fd, tracker_bizobj.FindFieldDef('ESTDAYS', config))
112 self.assertIsNone(tracker_bizobj.FindFieldDef('Unknown', config))
113
114 def testFindFieldDefByID_Empty(self):
115 config = tracker_pb2.ProjectIssueConfig()
116 self.assertIsNone(tracker_bizobj.FindFieldDefByID(1, config))
117
118 def testFindFieldDefByID_Default(self):
119 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
120 self.assertIsNone(tracker_bizobj.FindFieldDefByID(1, config))
121
122 def testFindFieldDefByID_Normal(self):
123 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
124 fd = tracker_pb2.FieldDef(field_id=1)
125 config.field_defs = [fd]
126 self.assertEqual(fd, tracker_bizobj.FindFieldDefByID(1, config))
127 self.assertIsNone(tracker_bizobj.FindFieldDefByID(99, config))
128
129 def testFindApprovalDef_Empty(self):
130 config = tracker_pb2.ProjectIssueConfig()
131 self.assertEqual(None, tracker_bizobj.FindApprovalDef(
132 'Nonexistent', config))
133
134 def testFindApprovalDef_Normal(self):
135 config = tracker_pb2.ProjectIssueConfig()
136 approval_fd = tracker_pb2.FieldDef(field_id=1, field_name='UIApproval')
137 approval_def = tracker_pb2.ApprovalDef(
138 approval_id=1, approver_ids=[111], survey='')
139 config.field_defs = [approval_fd]
140 config.approval_defs = [approval_def]
141 self.assertEqual(approval_def, tracker_bizobj.FindApprovalDef(
142 'UIApproval', config))
143
144 def testFindApprovalDef_NotApproval(self):
145 config = tracker_pb2.ProjectIssueConfig()
146 field_def = tracker_pb2.FieldDef(field_id=1, field_name='DesignDoc')
147 config.field_defs = [field_def]
148 self.assertEqual(None, tracker_bizobj.FindApprovalDef('DesignDoc', config))
149
150 def testFindApprovalDefByID_Empty(self):
151 config = tracker_pb2.ProjectIssueConfig()
152 self.assertEqual(None, tracker_bizobj.FindApprovalDefByID(1, config))
153
154 def testFindApprovalDefByID_Normal(self):
155 config = tracker_pb2.ProjectIssueConfig()
156 approval_def = tracker_pb2.ApprovalDef(
157 approval_id=1, approver_ids=[111, 222], survey='')
158 config.approval_defs = [approval_def]
159 self.assertEqual(approval_def, tracker_bizobj.FindApprovalDefByID(
160 1, config))
161 self.assertEqual(None, tracker_bizobj.FindApprovalDefByID(99, config))
162
163 def testFindApprovalValueByID_Normal(self):
164 av_24 = tracker_pb2.ApprovalValue(approval_id=24)
165 av_22 = tracker_pb2.ApprovalValue()
166 self.assertEqual(
167 av_24, tracker_bizobj.FindApprovalValueByID(24, [av_22, av_24]))
168
169 def testFindApprovalValueByID_None(self):
170 av_no_id = tracker_pb2.ApprovalValue()
171 self.assertIsNone(tracker_bizobj.FindApprovalValueByID(24, [av_no_id]))
172
173 def testFindApprovalsSubfields(self):
174 config = tracker_pb2.ProjectIssueConfig()
175 subfd_1 = tracker_pb2.FieldDef(approval_id=1)
176 subfd_2 = tracker_pb2.FieldDef(approval_id=2)
177 subfd_3 = tracker_pb2.FieldDef(approval_id=1)
178 subfd_4 = tracker_pb2.FieldDef()
179 config.field_defs = [subfd_1, subfd_2, subfd_3, subfd_4]
180
181 subfields_dict = tracker_bizobj.FindApprovalsSubfields([1, 2], config)
182 self.assertItemsEqual(subfields_dict[1], [subfd_1, subfd_3])
183 self.assertItemsEqual(subfields_dict[2], [subfd_2])
184 self.assertItemsEqual(subfields_dict[3], [])
185
186 def testFindPhaseByID_Normal(self):
187 canary_phase = tracker_pb2.Phase(phase_id=2, name='Canary')
188 stable_phase = tracker_pb2.Phase(name='Stable')
189 self.assertEqual(
190 canary_phase,
191 tracker_bizobj.FindPhaseByID(2, [stable_phase, canary_phase]))
192
193 def testFindPhaseByID_None(self):
194 stable_phase = tracker_pb2.Phase(name='Stable')
195 self.assertIsNone(tracker_bizobj.FindPhaseByID(42, [stable_phase]))
196
197 def testFindPhase_Normal(self):
198 canary_phase = tracker_pb2.Phase(phase_id=2)
199 stable_phase = tracker_pb2.Phase(name='Stable')
200 self.assertEqual(stable_phase, tracker_bizobj.FindPhase(
201 'Stable', [stable_phase, canary_phase]))
202
203 def testFindPhase_None(self):
204 self.assertIsNone(tracker_bizobj.FindPhase('ghost_phase', []))
205
206 def testGetGrantedPerms_Empty(self):
207 config = tracker_pb2.ProjectIssueConfig()
208 issue = tracker_pb2.Issue()
209 self.assertEqual(
210 set(), tracker_bizobj.GetGrantedPerms(issue, {111}, config))
211
212 def testGetGrantedPerms_Default(self):
213 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
214 issue = tracker_pb2.Issue()
215 self.assertEqual(
216 set(), tracker_bizobj.GetGrantedPerms(issue, {111}, config))
217
218 def testGetGrantedPerms_NothingGranted(self):
219 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
220 fd = tracker_pb2.FieldDef(field_id=1) # Nothing granted
221 config.field_defs = [fd]
222 fv = tracker_pb2.FieldValue(field_id=1, user_id=222)
223 issue = tracker_pb2.Issue(field_values=[fv])
224 self.assertEqual(
225 set(),
226 tracker_bizobj.GetGrantedPerms(issue, {111, 222}, config))
227
228 def testGetGrantedPerms_Normal(self):
229 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
230 fd = tracker_pb2.FieldDef(field_id=1, grants_perm='Highlight')
231 config.field_defs = [fd]
232 fv = tracker_pb2.FieldValue(field_id=1, user_id=222)
233 issue = tracker_pb2.Issue(field_values=[fv])
234 self.assertEqual(
235 set(),
236 tracker_bizobj.GetGrantedPerms(issue, {111}, config))
237 self.assertEqual(
238 set(['highlight']),
239 tracker_bizobj.GetGrantedPerms(issue, {111, 222}, config))
240
241 def testLabelsByPrefix(self):
242 expected = tracker_bizobj.LabelsByPrefix(
243 ['OneWordLabel', 'Key-Value1', 'Key-Value2', 'Launch-X-Y-Z'],
244 ['launch-x'])
245 self.assertEqual(
246 {'key': ['Value1', 'Value2'],
247 'launch-x': ['Y-Z']},
248 expected)
249
250 def testLabelIsMaskedByField(self):
251 self.assertIsNone(tracker_bizobj.LabelIsMaskedByField('UI', []))
252 self.assertIsNone(tracker_bizobj.LabelIsMaskedByField('P-1', []))
253 field_names = ['priority', 'size']
254 self.assertIsNone(tracker_bizobj.LabelIsMaskedByField(
255 'UI', field_names))
256 self.assertIsNone(tracker_bizobj.LabelIsMaskedByField(
257 'OS-All', field_names))
258 self.assertEqual(
259 'size', tracker_bizobj.LabelIsMaskedByField('size-xl', field_names))
260 self.assertEqual(
261 'size', tracker_bizobj.LabelIsMaskedByField('Size-XL', field_names))
262
263 def testNonMaskedLabels(self):
264 self.assertEqual([], tracker_bizobj.NonMaskedLabels([], []))
265 field_names = ['priority', 'size']
266 self.assertEqual([], tracker_bizobj.NonMaskedLabels([], field_names))
267 self.assertEqual(
268 [], tracker_bizobj.NonMaskedLabels(['Size-XL'], field_names))
269 self.assertEqual(
270 ['Hot'], tracker_bizobj.NonMaskedLabels(['Hot'], field_names))
271 self.assertEqual(
272 ['Hot'],
273 tracker_bizobj.NonMaskedLabels(['Hot', 'Size-XL'], field_names))
274
275 def testMakeApprovalValue_Basic(self):
276 av = tracker_bizobj.MakeApprovalValue(2)
277 expected = tracker_pb2.ApprovalValue(approval_id=2)
278 self.assertEqual(av, expected)
279
280 def testMakeApprovalValue_Full(self):
281 av = tracker_bizobj.MakeApprovalValue(
282 2, approver_ids=[], status=tracker_pb2.ApprovalStatus.APPROVED,
283 setter_id=3, set_on=123, phase_id=3)
284 expected = tracker_pb2.ApprovalValue(
285 approval_id=2, approver_ids=[],
286 status=tracker_pb2.ApprovalStatus.APPROVED,
287 setter_id=3, set_on=123, phase_id=3)
288 self.assertEqual(av, expected)
289
290 def testMakeFieldDef_Basic(self):
291 fd = tracker_bizobj.MakeFieldDef(
292 1, 789, 'Size', tracker_pb2.FieldTypes.USER_TYPE, None, None,
293 False, False, False, None, None, None, False,
294 None, None, None, 'no_action', 'Some field', False)
295 self.assertEqual(1, fd.field_id)
296 self.assertEqual(None, fd.approval_id)
297 self.assertFalse(fd.is_phase_field)
298 self.assertFalse(fd.is_restricted_field)
299
300 def testMakeFieldDef_Full(self):
301 fd = tracker_bizobj.MakeFieldDef(
302 1,
303 789,
304 'Size',
305 tracker_pb2.FieldTypes.INT_TYPE,
306 None,
307 None,
308 False,
309 False,
310 False,
311 1,
312 100,
313 None,
314 False,
315 None,
316 None,
317 None,
318 'no_action',
319 'Some field',
320 False,
321 approval_id=4,
322 is_phase_field=True,
323 is_restricted_field=True)
324 self.assertEqual(1, fd.min_value)
325 self.assertEqual(100, fd.max_value)
326 self.assertEqual(4, fd.approval_id)
327 self.assertTrue(fd.is_phase_field)
328 self.assertTrue(fd.is_restricted_field)
329
330 fd = tracker_bizobj.MakeFieldDef(
331 1,
332 789,
333 'Size',
334 tracker_pb2.FieldTypes.STR_TYPE,
335 None,
336 None,
337 False,
338 False,
339 False,
340 None,
341 None,
342 'A.*Z',
343 False,
344 'EditIssue',
345 None,
346 None,
347 'no_action',
348 'Some field',
349 False,
350 4,
351 is_restricted_field=False)
352 self.assertEqual('A.*Z', fd.regex)
353 self.assertEqual('EditIssue', fd.needs_perm)
354 self.assertEqual(4, fd.approval_id)
355 self.assertFalse(fd.is_restricted_field)
356
357 def testMakeFieldDef_IntBools(self):
358 fd = tracker_bizobj.MakeFieldDef(
359 1,
360 789,
361 'Size',
362 tracker_pb2.FieldTypes.INT_TYPE,
363 None,
364 None,
365 0,
366 0,
367 0,
368 1,
369 100,
370 None,
371 0,
372 None,
373 None,
374 None,
375 'no_action',
376 'Some field',
377 0,
378 approval_id=4,
379 is_phase_field=1,
380 is_restricted_field=1)
381 self.assertFalse(fd.is_required)
382 self.assertFalse(fd.is_niche)
383 self.assertFalse(fd.is_multivalued)
384 self.assertFalse(fd.needs_member)
385 self.assertFalse(fd.is_deleted)
386 self.assertTrue(fd.is_phase_field)
387 self.assertTrue(fd.is_restricted_field)
388
389 def testMakeFieldValue(self):
390 # Only the first value counts.
391 fv = tracker_bizobj.MakeFieldValue(1, 42, 'yay', 111, None, None, True)
392 self.assertEqual(1, fv.field_id)
393 self.assertEqual(42, fv.int_value)
394 self.assertIsNone(fv.str_value)
395 self.assertEqual(None, fv.user_id)
396 self.assertEqual(None, fv.phase_id)
397
398 fv = tracker_bizobj.MakeFieldValue(1, None, 'yay', 111, None, None, True)
399 self.assertEqual('yay', fv.str_value)
400 self.assertEqual(None, fv.user_id)
401
402 fv = tracker_bizobj.MakeFieldValue(1, None, None, 111, None, None, True)
403 self.assertEqual(111, fv.user_id)
404 self.assertEqual(True, fv.derived)
405
406 fv = tracker_bizobj.MakeFieldValue(
407 1, None, None, None, 1234567890, None, True)
408 self.assertEqual(1234567890, fv.date_value)
409 self.assertEqual(True, fv.derived)
410
411 fv = tracker_bizobj.MakeFieldValue(
412 1, None, None, None, None, 'www.google.com', True, phase_id=1)
413 self.assertEqual('www.google.com', fv.url_value)
414 self.assertEqual(True, fv.derived)
415 self.assertEqual(1, fv.phase_id)
416
417 with self.assertRaises(ValueError):
418 tracker_bizobj.MakeFieldValue(1, None, None, None, None, None, True)
419
420 def testGetFieldValueWithRawValue(self):
421 class MockUser(object):
422 def __init__(self):
423 self.email = 'test@example.com'
424 users_by_id = {111: MockUser()}
425
426 class MockFieldValue(object):
427 def __init__(
428 self, int_value=None, str_value=None, user_id=None,
429 date_value=None, url_value=None):
430 self.int_value = int_value
431 self.str_value = str_value
432 self.user_id = user_id
433 self.date_value = date_value
434 self.url_value = url_value
435
436 # Test user types.
437 # Use user_id from the field_value and get user from users_by_id.
438 val = tracker_bizobj.GetFieldValueWithRawValue(
439 field_type=tracker_pb2.FieldTypes.USER_TYPE,
440 users_by_id=users_by_id,
441 field_value=MockFieldValue(user_id=111),
442 raw_value=113,
443 )
444 self.assertEqual('test@example.com', val)
445 # Specify user_id that does not exist in users_by_id.
446 val = tracker_bizobj.GetFieldValueWithRawValue(
447 field_type=tracker_pb2.FieldTypes.USER_TYPE,
448 users_by_id=users_by_id,
449 field_value=MockFieldValue(user_id=112),
450 raw_value=113,
451 )
452 self.assertEqual(112, val)
453 # Pass in empty users_by_id.
454 val = tracker_bizobj.GetFieldValueWithRawValue(
455 field_type=tracker_pb2.FieldTypes.USER_TYPE,
456 users_by_id={},
457 field_value=MockFieldValue(user_id=111),
458 raw_value=113,
459 )
460 self.assertEqual(111, val)
461 # Test different raw_values.
462 raw_value_tests = (
463 (111, 'test@example.com'),
464 (112, 112),
465 (framework_constants.NO_USER_NAME, framework_constants.NO_USER_NAME))
466 for (raw_value, expected_output) in raw_value_tests:
467 val = tracker_bizobj.GetFieldValueWithRawValue(
468 field_type=tracker_pb2.FieldTypes.USER_TYPE,
469 users_by_id=users_by_id,
470 field_value=None,
471 raw_value=raw_value,
472 )
473 self.assertEqual(expected_output, val)
474
475 # Test enum types.
476 # The returned value should be the raw_value regardless of field_value being
477 # specified.
478 for field_value in (MockFieldValue(), None):
479 val = tracker_bizobj.GetFieldValueWithRawValue(
480 field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
481 users_by_id=users_by_id,
482 field_value=field_value,
483 raw_value='abc',
484 )
485 self.assertEqual('abc', val)
486
487 # Test int type.
488 # Use int_value from the field_value.
489 val = tracker_bizobj.GetFieldValueWithRawValue(
490 field_type=tracker_pb2.FieldTypes.INT_TYPE,
491 users_by_id=users_by_id,
492 field_value=MockFieldValue(int_value=100),
493 raw_value=101,
494 )
495 self.assertEqual(100, val)
496 # Use the raw_value when field_value is not specified.
497 val = tracker_bizobj.GetFieldValueWithRawValue(
498 field_type=tracker_pb2.FieldTypes.INT_TYPE,
499 users_by_id=users_by_id,
500 field_value=None,
501 raw_value=101,
502 )
503 self.assertEqual(101, val)
504
505 # Test str type.
506 # Use str_value from the field_value.
507 val = tracker_bizobj.GetFieldValueWithRawValue(
508 field_type=tracker_pb2.FieldTypes.STR_TYPE,
509 users_by_id=users_by_id,
510 field_value=MockFieldValue(str_value='testing'),
511 raw_value='test',
512 )
513 self.assertEqual('testing', val)
514 # Use the raw_value when field_value is not specified.
515 val = tracker_bizobj.GetFieldValueWithRawValue(
516 field_type=tracker_pb2.FieldTypes.STR_TYPE,
517 users_by_id=users_by_id,
518 field_value=None,
519 raw_value='test',
520 )
521 self.assertEqual('test', val)
522
523 # Test date type.
524 # Use date_value from the field_value.
525 val = tracker_bizobj.GetFieldValueWithRawValue(
526 field_type=tracker_pb2.FieldTypes.DATE_TYPE,
527 users_by_id=users_by_id,
528 field_value=MockFieldValue(date_value=1234567890),
529 raw_value=2345678901,
530 )
531 self.assertEqual('2009-02-13', val)
532 # Use the raw_value when field_value is not specified.
533 val = tracker_bizobj.GetFieldValueWithRawValue(
534 field_type=tracker_pb2.FieldTypes.DATE_TYPE,
535 users_by_id=users_by_id,
536 field_value=None,
537 raw_value='2016-10-30',
538 )
539 self.assertEqual('2016-10-30', val)
540
541 def testFindComponentDef_Empty(self):
542 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
543 actual = tracker_bizobj.FindComponentDef('DB', config)
544 self.assertIsNone(actual)
545
546 def testFindComponentDef_NoMatch(self):
547 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
548 cd = tracker_pb2.ComponentDef(path='UI>Splash')
549 config.component_defs.append(cd)
550 actual = tracker_bizobj.FindComponentDef('DB', config)
551 self.assertIsNone(actual)
552
553 def testFindComponentDef_MatchFound(self):
554 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
555 cd = tracker_pb2.ComponentDef(path='UI>Splash')
556 config.component_defs.append(cd)
557 actual = tracker_bizobj.FindComponentDef('UI>Splash', config)
558 self.assertEqual(cd, actual)
559
560 def testFindMatchingComponentIDs_Empty(self):
561 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
562 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config)
563 self.assertEqual([], actual)
564 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config, exact=False)
565 self.assertEqual([], actual)
566
567 def testFindMatchingComponentIDs_NoMatch(self):
568 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
569 config.component_defs.append(tracker_pb2.ComponentDef(
570 component_id=1, path='UI>Splash'))
571 config.component_defs.append(tracker_pb2.ComponentDef(
572 component_id=2, path='UI>AboutBox'))
573 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config)
574 self.assertEqual([], actual)
575 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config, exact=False)
576 self.assertEqual([], actual)
577
578 def testFindMatchingComponentIDs_Match(self):
579 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
580 config.component_defs.append(tracker_pb2.ComponentDef(
581 component_id=1, path='UI>Splash'))
582 config.component_defs.append(tracker_pb2.ComponentDef(
583 component_id=2, path='UI>AboutBox'))
584 config.component_defs.append(tracker_pb2.ComponentDef(
585 component_id=3, path='DB>Attachments'))
586 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config)
587 self.assertEqual([], actual)
588 actual = tracker_bizobj.FindMatchingComponentIDs('DB', config, exact=False)
589 self.assertEqual([3], actual)
590
591 def testFindMatchingComponentIDs_MatchMultiple(self):
592 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
593 config.component_defs.append(tracker_pb2.ComponentDef(
594 component_id=1, path='UI>Splash'))
595 config.component_defs.append(tracker_pb2.ComponentDef(
596 component_id=2, path='UI>AboutBox'))
597 config.component_defs.append(tracker_pb2.ComponentDef(
598 component_id=22, path='UI>AboutBox'))
599 config.component_defs.append(tracker_pb2.ComponentDef(
600 component_id=3, path='DB>Attachments'))
601 actual = tracker_bizobj.FindMatchingComponentIDs('UI>AboutBox', config)
602 self.assertEqual([2, 22], actual)
603 actual = tracker_bizobj.FindMatchingComponentIDs('UI', config, exact=False)
604 self.assertEqual([1, 2, 22], actual)
605
606 def testFindComponentDefByID_Empty(self):
607 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
608 actual = tracker_bizobj.FindComponentDefByID(999, config)
609 self.assertIsNone(actual)
610
611 def testFindComponentDefByID_NoMatch(self):
612 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
613 config.component_defs.append(tracker_pb2.ComponentDef(
614 component_id=1, path='UI>Splash'))
615 config.component_defs.append(tracker_pb2.ComponentDef(
616 component_id=2, path='UI>AboutBox'))
617 actual = tracker_bizobj.FindComponentDefByID(999, config)
618 self.assertIsNone(actual)
619
620 def testFindComponentDefByID_MatchFound(self):
621 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
622 cd = tracker_pb2.ComponentDef(component_id=1, path='UI>Splash')
623 config.component_defs.append(cd)
624 config.component_defs.append(tracker_pb2.ComponentDef(
625 component_id=2, path='UI>AboutBox'))
626 actual = tracker_bizobj.FindComponentDefByID(1, config)
627 self.assertEqual(cd, actual)
628
629 def testFindAncestorComponents_Empty(self):
630 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
631 cd = tracker_pb2.ComponentDef(component_id=1, path='UI>Splash')
632 actual = tracker_bizobj.FindAncestorComponents(config, cd)
633 self.assertEqual([], actual)
634
635 def testFindAncestorComponents_NoMatch(self):
636 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
637 cd = tracker_pb2.ComponentDef(component_id=1, path='UI>Splash')
638 config.component_defs.append(tracker_pb2.ComponentDef(
639 component_id=2, path='UI>AboutBox'))
640 actual = tracker_bizobj.FindAncestorComponents(config, cd)
641 self.assertEqual([], actual)
642
643 def testFindAncestorComponents_NoComponents(self):
644 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
645 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
646 config.component_defs.append(cd)
647 cd2 = tracker_pb2.ComponentDef(component_id=2, path='UI>Splash')
648 config.component_defs.append(cd2)
649 actual = tracker_bizobj.FindAncestorComponents(config, cd2)
650 self.assertEqual([cd], actual)
651
652 def testGetIssueComponentsAndAncestors_NoSuchComponent(self):
653 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
654 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
655 config.component_defs.append(cd)
656 cd2 = tracker_pb2.ComponentDef(component_id=2, path='UI>Splash')
657 config.component_defs.append(cd2)
658 issue = tracker_pb2.Issue(component_ids=[999])
659 actual = tracker_bizobj.GetIssueComponentsAndAncestors(issue, config)
660 self.assertEqual([], actual)
661
662 def testGetIssueComponentsAndAncestors_AffectsNoComponents(self):
663 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
664 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
665 config.component_defs.append(cd)
666 cd2 = tracker_pb2.ComponentDef(component_id=2, path='UI>Splash')
667 config.component_defs.append(cd2)
668 issue = tracker_pb2.Issue(component_ids=[])
669 actual = tracker_bizobj.GetIssueComponentsAndAncestors(issue, config)
670 self.assertEqual([], actual)
671
672 def testGetIssueComponentsAndAncestors_AffectsSomeComponents(self):
673 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
674 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
675 config.component_defs.append(cd)
676 cd2 = tracker_pb2.ComponentDef(component_id=2, path='UI>Splash')
677 config.component_defs.append(cd2)
678 issue = tracker_pb2.Issue(component_ids=[2])
679 actual = tracker_bizobj.GetIssueComponentsAndAncestors(issue, config)
680 self.assertEqual([cd, cd2], actual)
681
682 def testFindDescendantComponents_Empty(self):
683 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
684 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
685 actual = tracker_bizobj.FindDescendantComponents(config, cd)
686 self.assertEqual([], actual)
687
688 def testFindDescendantComponents_NoMatch(self):
689 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
690 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
691 config.component_defs.append(cd)
692 actual = tracker_bizobj.FindDescendantComponents(config, cd)
693 self.assertEqual([], actual)
694
695 def testFindDescendantComponents_SomeMatch(self):
696 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
697 cd = tracker_pb2.ComponentDef(component_id=1, path='UI')
698 config.component_defs.append(cd)
699 cd2 = tracker_pb2.ComponentDef(component_id=2, path='UI>Splash')
700 config.component_defs.append(cd2)
701 actual = tracker_bizobj.FindDescendantComponents(config, cd)
702 self.assertEqual([cd2], actual)
703
704 def testMakeComponentDef(self):
705 cd = tracker_bizobj.MakeComponentDef(
706 1, 789, 'UI', 'doc', False, [111], [222], 1234567890,
707 111)
708 self.assertEqual(1, cd.component_id)
709 self.assertEqual([111], cd.admin_ids)
710 self.assertEqual([], cd.label_ids)
711
712 def testMakeSavedQuery_WithNone(self):
713 sq = tracker_bizobj.MakeSavedQuery(
714 None, 'my query', 2, 'priority:high')
715 self.assertEqual(None, sq.query_id)
716 self.assertEqual(None, sq.subscription_mode)
717 self.assertEqual([], sq.executes_in_project_ids)
718
719 def testMakeSavedQuery(self):
720 sq = tracker_bizobj.MakeSavedQuery(
721 100, 'my query', 2, 'priority:high',
722 subscription_mode='immediate', executes_in_project_ids=[789])
723 self.assertEqual(100, sq.query_id)
724 self.assertEqual('immediate', sq.subscription_mode)
725 self.assertEqual([789], sq.executes_in_project_ids)
726
727 def testConvertDictToTemplate(self):
728 template = tracker_bizobj.ConvertDictToTemplate(
729 dict(name='name', content='content', summary='summary',
730 status='status', owner_id=111))
731 self.assertEqual('name', template.name)
732 self.assertEqual('content', template.content)
733 self.assertEqual('summary', template.summary)
734 self.assertEqual('status', template.status)
735 self.assertEqual(111, template.owner_id)
736 self.assertFalse(template.summary_must_be_edited)
737 self.assertTrue(template.owner_defaults_to_member)
738 self.assertFalse(template.component_required)
739
740 template = tracker_bizobj.ConvertDictToTemplate(
741 dict(name='name', content='content', labels=['a', 'b', 'c']))
742 self.assertListEqual(
743 ['a', 'b', 'c'], list(template.labels))
744
745 template = tracker_bizobj.ConvertDictToTemplate(
746 dict(name='name', content='content', summary_must_be_edited=True,
747 owner_defaults_to_member=True, component_required=True))
748 self.assertTrue(template.summary_must_be_edited)
749 self.assertTrue(template.owner_defaults_to_member)
750 self.assertTrue(template.component_required)
751
752 template = tracker_bizobj.ConvertDictToTemplate(
753 dict(name='name', content='content', summary_must_be_edited=False,
754 owner_defaults_to_member=False, component_required=False))
755 self.assertFalse(template.summary_must_be_edited)
756 self.assertFalse(template.owner_defaults_to_member)
757 self.assertFalse(template.component_required)
758
759 def CheckDefaultConfig(self, config):
760 self.assertTrue(len(config.well_known_statuses) > 0)
761 self.assertTrue(config.statuses_offer_merge > 0)
762 self.assertTrue(len(config.well_known_labels) > 0)
763 self.assertTrue(len(config.exclusive_label_prefixes) > 0)
764 # TODO(jrobbins): test actual values from default config
765
766 def testMakeDefaultProjectIssueConfig(self):
767 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
768 config.default_template_for_developers = 1
769 config.default_template_for_users = 2
770 self.CheckDefaultConfig(config)
771
772 def testHarmonizeConfigs_Empty(self):
773 harmonized = tracker_bizobj.HarmonizeConfigs([])
774 self.CheckDefaultConfig(harmonized)
775
776 def testHarmonizeConfigs(self):
777 c1 = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
778 harmonized = tracker_bizobj.HarmonizeConfigs([c1])
779 self.assertListEqual(
780 [stat.status for stat in c1.well_known_statuses],
781 [stat.status for stat in harmonized.well_known_statuses])
782 self.assertListEqual(
783 [lab.label for lab in c1.well_known_labels],
784 [lab.label for lab in harmonized.well_known_labels])
785 self.assertEqual('', harmonized.default_sort_spec)
786
787 c2 = tracker_bizobj.MakeDefaultProjectIssueConfig(678)
788 tracker_bizobj.SetConfigStatuses(c2, [
789 ('Unconfirmed', '', True, False),
790 ('New', '', True, True),
791 ('Accepted', '', True, False),
792 ('Begun', '', True, False),
793 ('Fixed', '', False, False),
794 ('Obsolete', '', False, False)])
795 tracker_bizobj.SetConfigLabels(c2, [
796 ('Pri-0', '', False),
797 ('Priority-High', '', True),
798 ('Pri-1', '', False),
799 ('Priority-Medium', '', True),
800 ('Pri-2', '', False),
801 ('Priority-Low', '', True),
802 ('Pri-3', '', False),
803 ('Pri-4', '', False)])
804 c2.default_sort_spec = 'Pri -status'
805
806 c1.approval_defs = [
807 tracker_pb2.ApprovalDef(approval_id=1),
808 tracker_pb2.ApprovalDef(approval_id=3),
809 ]
810 c1.field_defs = [
811 tracker_pb2.FieldDef(
812 field_id=1, project_id=789, field_name='CowApproval',
813 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
814 tracker_pb2.FieldDef(
815 field_id=3, project_id=789, field_name='MooApproval',
816 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
817 ]
818 c2.approval_defs = [
819 tracker_pb2.ApprovalDef(approval_id=2),
820 ]
821 c2.field_defs = [
822 tracker_pb2.FieldDef(
823 field_id=2, project_id=788, field_name='CowApproval',
824 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
825 ]
826 harmonized = tracker_bizobj.HarmonizeConfigs([c1, c2])
827 result_statuses = [stat.status
828 for stat in harmonized.well_known_statuses]
829 result_labels = [lab.label
830 for lab in harmonized.well_known_labels]
831 self.assertListEqual(
832 ['Unconfirmed', 'New', 'Accepted', 'Begun', 'Started', 'Fixed',
833 'Obsolete', 'Verified', 'Invalid', 'Duplicate', 'WontFix', 'Done'],
834 result_statuses)
835 self.assertListEqual(
836 ['Pri-0', 'Type-Defect', 'Type-Enhancement', 'Type-Task',
837 'Type-Other', 'Priority-Critical', 'Priority-High',
838 'Pri-1', 'Priority-Medium', 'Pri-2', 'Priority-Low', 'Pri-3',
839 'Pri-4'],
840 result_labels[:result_labels.index('OpSys-All')])
841 self.assertEqual('Pri -status', harmonized.default_sort_spec.strip())
842 self.assertItemsEqual(c1.field_defs + c2.field_defs,
843 harmonized.field_defs)
844 self.assertItemsEqual(c1.approval_defs + c2.approval_defs,
845 harmonized.approval_defs)
846
847 def testHarmonizeConfigsMeansOpen(self):
848 c1 = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
849 c2 = tracker_bizobj.MakeDefaultProjectIssueConfig(678)
850 means_open = [("TT", True, True),
851 ("TF", True, False),
852 ("FT", False, True),
853 ("FF", False, False)]
854 tracker_bizobj.SetConfigStatuses(c1, [
855 (x[0], x[0], x[1], False)
856 for x in means_open])
857 tracker_bizobj.SetConfigStatuses(c2, [
858 (x[0], x[0], x[2], False)
859 for x in means_open])
860
861 harmonized = tracker_bizobj.HarmonizeConfigs([c1, c2])
862 for stat in harmonized.well_known_statuses:
863 self.assertEqual(stat.means_open, stat.status != "FF")
864
865 def testHarmonizeConfigs_DeletedCustomField(self):
866 """Only non-deleted custom fields in configs are included."""
867 harmonized = tracker_bizobj.HarmonizeConfigs([self.config])
868 self.assertEqual(1, len(harmonized.field_defs))
869
870 self.config.field_defs[0].is_deleted = True
871 harmonized = tracker_bizobj.HarmonizeConfigs([self.config])
872 self.assertEqual(0, len(harmonized.field_defs))
873
874 def testHarmonizeLabelOrStatusRows_Empty(self):
875 def_rows = []
876 actual = tracker_bizobj.HarmonizeLabelOrStatusRows(def_rows)
877 self.assertEqual([], actual)
878
879 def testHarmonizeLabelOrStatusRows_Normal(self):
880 def_rows = [
881 (100, 789, 1, 'Priority-High'),
882 (101, 789, 2, 'Priority-Normal'),
883 (103, 789, 3, 'Priority-Low'),
884 (199, 789, None, 'Monday'),
885 (200, 678, 1, 'Priority-High'),
886 (201, 678, 2, 'Priority-Medium'),
887 (202, 678, 3, 'Priority-Low'),
888 (299, 678, None, 'Hot'),
889 ]
890 actual = tracker_bizobj.HarmonizeLabelOrStatusRows(def_rows)
891 self.assertEqual(
892 [(199, None, 'Monday'),
893 (299, None, 'Hot'),
894 (200, 1, 'Priority-High'),
895 (100, 1, 'Priority-High'),
896 (101, 2, 'Priority-Normal'),
897 (201, 2, 'Priority-Medium'),
898 (202, 3, 'Priority-Low'),
899 (103, 3, 'Priority-Low')
900 ],
901 actual)
902
903 def testCombineOrderedLists_Empty(self):
904 self.assertEqual([], tracker_bizobj._CombineOrderedLists([]))
905
906 def testCombineOrderedLists_Normal(self):
907 a = ['Mon', 'Wed', 'Fri']
908 b = ['Mon', 'Tue']
909 c = ['Wed', 'Thu']
910 self.assertEqual(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
911 tracker_bizobj._CombineOrderedLists([a, b, c]))
912
913 d = ['Mon', 'StartOfWeek', 'Wed', 'MidWeek', 'Fri', 'EndOfWeek']
914 self.assertEqual(['Mon', 'StartOfWeek', 'Tue', 'Wed', 'MidWeek', 'Thu',
915 'Fri', 'EndOfWeek'],
916 tracker_bizobj._CombineOrderedLists([a, b, c, d]))
917
918 def testAccumulateCombinedList_Empty(self):
919 combined_items = []
920 combined_keys = []
921 seen_keys_set = set()
922 tracker_bizobj._AccumulateCombinedList(
923 [], combined_items, combined_keys, seen_keys_set)
924 self.assertEqual([], combined_items)
925 self.assertEqual([], combined_keys)
926 self.assertEqual(set(), seen_keys_set)
927
928 def testAccumulateCombinedList_Normal(self):
929 combined_items = ['a', 'b', 'C']
930 combined_keys = ['a', 'b', 'c'] # Keys are always lowercased
931 seen_keys_set = set(['a', 'b', 'c'])
932 tracker_bizobj._AccumulateCombinedList(
933 ['b', 'x', 'C', 'd', 'a'], combined_items, combined_keys, seen_keys_set)
934 self.assertEqual(['a', 'b', 'x', 'C', 'd'], combined_items)
935 self.assertEqual(['a', 'b', 'x', 'c', 'd'], combined_keys)
936 self.assertEqual(set(['a', 'b', 'x', 'c', 'd']), seen_keys_set)
937
938 def testAccumulateCombinedList_NormalWithKeyFunction(self):
939 combined_items = ['A', 'B', 'C']
940 combined_keys = ['@a', '@b', '@c']
941 seen_keys_set = set(['@a', '@b', '@c'])
942 tracker_bizobj._AccumulateCombinedList(
943 ['B', 'X', 'c', 'D', 'A'], combined_items, combined_keys, seen_keys_set,
944 key=lambda s: '@' + s)
945 self.assertEqual(['A', 'B', 'X', 'C', 'D'], combined_items)
946 self.assertEqual(['@a', '@b', '@x', '@c', '@d'], combined_keys)
947 self.assertEqual(set(['@a', '@b', '@x', '@c', '@d']), seen_keys_set)
948
949 def testGetBuiltInQuery(self):
950 self.assertEqual(
951 'is:open', tracker_bizobj.GetBuiltInQuery(2))
952 self.assertEqual(
953 '', tracker_bizobj.GetBuiltInQuery(101))
954
955 def testUsersInvolvedInComment(self):
956 comment = tracker_pb2.IssueComment()
957 self.assertEqual({0}, tracker_bizobj.UsersInvolvedInComment(comment))
958
959 comment.user_id = 111
960 self.assertEqual(
961 {111}, tracker_bizobj.UsersInvolvedInComment(comment))
962
963 amendment = tracker_pb2.Amendment(newvalue='foo')
964 comment.amendments.append(amendment)
965 self.assertEqual(
966 {111}, tracker_bizobj.UsersInvolvedInComment(comment))
967
968 amendment.added_user_ids.append(222)
969 amendment.removed_user_ids.append(333)
970 self.assertEqual({111, 222, 333},
971 tracker_bizobj.UsersInvolvedInComment(comment))
972
973 def testUsersInvolvedInCommentList(self):
974 self.assertEqual(set(), tracker_bizobj.UsersInvolvedInCommentList([]))
975
976 c1 = tracker_pb2.IssueComment()
977 c1.user_id = 111
978 c1.amendments.append(tracker_pb2.Amendment(newvalue='foo'))
979
980 c2 = tracker_pb2.IssueComment()
981 c2.user_id = 111
982 c2.amendments.append(tracker_pb2.Amendment(
983 added_user_ids=[222], removed_user_ids=[333]))
984
985 self.assertEqual({111},
986 tracker_bizobj.UsersInvolvedInCommentList([c1]))
987
988 self.assertEqual({111, 222, 333},
989 tracker_bizobj.UsersInvolvedInCommentList([c2]))
990
991 self.assertEqual({111, 222, 333},
992 tracker_bizobj.UsersInvolvedInCommentList([c1, c2]))
993
994 def testUsersInvolvedInIssues_Empty(self):
995 self.assertEqual(set(), tracker_bizobj.UsersInvolvedInIssues([]))
996
997 def testUsersInvolvedInIssues_Normal(self):
998 av_1 = tracker_pb2.ApprovalValue(approver_ids=[666, 222, 444])
999 av_2 = tracker_pb2.ApprovalValue(approver_ids=[777], setter_id=888)
1000 issue1 = tracker_pb2.Issue(
1001 reporter_id=111, owner_id=222, cc_ids=[222, 333],
1002 approval_values=[av_1, av_2])
1003 issue2 = tracker_pb2.Issue(
1004 reporter_id=333, owner_id=444, derived_cc_ids=[222, 444])
1005 issue2.field_values = [tracker_pb2.FieldValue(user_id=555)]
1006 self.assertEqual(
1007 set([0, 111, 222, 333, 444, 555, 666, 777, 888]),
1008 tracker_bizobj.UsersInvolvedInIssues([issue1, issue2]))
1009
1010 def testUsersInvolvedInTemplate_Empty(self):
1011 template = tracker_bizobj.MakeIssueTemplate(
1012 'A report', 'Something went wrong', 'New', None, 'Look out!',
1013 ['Priority-High'], [], [], [])
1014 self.assertEqual(set(), tracker_bizobj.UsersInvolvedInTemplate(template))
1015
1016 def testUsersInvolvedInTemplate_Normal(self):
1017 template = tracker_bizobj.MakeIssueTemplate(
1018 'A report', 'Something went wrong', 'New', 111, 'Look out!',
1019 ['Priority-High'], [], [333, 444], [])
1020 template.field_values = [
1021 tracker_bizobj.MakeFieldValue(22, None, None, 222, None, None, False),
1022 tracker_bizobj.MakeFieldValue(23, None, None, 333, None, None, False),
1023 tracker_bizobj.MakeFieldValue(24, None, None, 222, None, None, False),
1024 tracker_bizobj.MakeFieldValue(25, None, 'pop', None, None, None, False)]
1025 template.approval_values = [
1026 tracker_pb2.ApprovalValue(
1027 approval_id=30, setter_id=666, approver_ids=[444, 555]),
1028 tracker_pb2.ApprovalValue(approval_id=31),
1029 ]
1030 self.assertEqual(
1031 {111, 333, 444, 222, 555, 666},
1032 tracker_bizobj.UsersInvolvedInTemplate(template))
1033
1034 def testUsersInvolvedInTemplates_NoTemplates(self):
1035 self.assertEqual(set(), tracker_bizobj.UsersInvolvedInTemplates([]))
1036
1037 def testUsersInvolvedInTemplates_Normal(self):
1038 template1 = tracker_bizobj.MakeIssueTemplate(
1039 'A report', 'Something went wrong', 'New', 111, 'Look out!',
1040 ['Priority-High'], [], [333, 444], [])
1041 template1.field_values = [
1042 tracker_bizobj.MakeFieldValue(22, None, None, 222, None, None, False)]
1043
1044 template2 = tracker_bizobj.MakeIssueTemplate(
1045 'dude', 'wheres my', 'New', 222, 'car', [], [], [999, 888], [])
1046 template2.field_values = [
1047 tracker_bizobj.MakeFieldValue(23, None, None, 333, None, None, False)]
1048 template2.approval_values = [
1049 tracker_pb2.ApprovalValue(
1050 approval_id=30, setter_id=666, approver_ids=[444, 555]),
1051 tracker_pb2.ApprovalValue(approval_id=31)]
1052
1053 self.assertEqual(
1054 {111, 333, 444, 222, 555, 666, 888, 999},
1055 tracker_bizobj.UsersInvolvedInTemplates([template1, template2]))
1056
1057 def testUsersInvolvedInApprovalDefs_Empty(self):
1058 """There are no user IDs given empty inputs"""
1059 actual = tracker_bizobj.UsersInvolvedInApprovalDefs([], [])
1060 self.assertEqual(set(), actual)
1061
1062 def testsersInvolvedInApprovalDefs_Normal(self):
1063 """We find user IDs mentioned in approval approvers and field admins"""
1064 self.config.field_defs[0].admin_ids = [111, 222]
1065 approval_def = tracker_pb2.ApprovalDef(
1066 approval_id=1, approver_ids=[111, 333], survey='')
1067 self.config.approval_defs = [approval_def]
1068 actual = tracker_bizobj.UsersInvolvedInApprovalDefs(
1069 [approval_def], [self.config.field_defs[0]])
1070 self.assertEqual({111, 222, 333}, actual)
1071
1072 def testUsersInvolvedInConfig_Empty(self):
1073 """There are no user IDs mentioned in a default config."""
1074 actual = tracker_bizobj.UsersInvolvedInConfig(self.config)
1075 self.assertEqual(set(), actual)
1076
1077 def testUsersInvolvedInConfig_Normal(self):
1078 """We find user IDs mentioned components, fields, and approvals."""
1079 self.config.component_defs[0].admin_ids = [111]
1080 self.config.component_defs[0].cc_ids = [444]
1081 self.config.field_defs[0].admin_ids = [111, 222]
1082 approval_def = tracker_pb2.ApprovalDef(
1083 approval_id=1, approver_ids=[111, 333], survey='')
1084 self.config.approval_defs = [approval_def]
1085 actual = tracker_bizobj.UsersInvolvedInConfig(self.config)
1086 self.assertEqual({111, 222, 333, 444}, actual)
1087
1088 def testLabelIDsInvolvedInConfig_Empty(self):
1089 """There are no label IDs mentioned in a default config."""
1090 actual = tracker_bizobj.LabelIDsInvolvedInConfig(self.config)
1091 self.assertEqual(set(), actual)
1092
1093 def testLabelIDsInvolvedInConfig_Normal(self):
1094 """We find label IDs added by components."""
1095 self.config.component_defs[0].label_ids = [1, 2, 3]
1096 actual = tracker_bizobj.LabelIDsInvolvedInConfig(self.config)
1097 self.assertEqual({1, 2, 3}, actual)
1098
1099 def testMakeApprovalDelta_AllSpecified(self):
1100 added_fv = tracker_bizobj.MakeFieldValue(
1101 1, None, 'added str', None, None, None, False)
1102 removed_fv = tracker_bizobj.MakeFieldValue(
1103 1, None, 'removed str', None, None, None, False)
1104 clear_fvs = [24]
1105 labels_add = ['ittly-bittly', 'piggly-wiggly']
1106 labels_remove = ['golly-goops', 'whoopsie']
1107 actual = tracker_bizobj.MakeApprovalDelta(
1108 tracker_pb2.ApprovalStatus.APPROVED, 111, [222], [],
1109 [added_fv], [removed_fv], clear_fvs, labels_add, labels_remove,
1110 set_on=1234)
1111 self.assertEqual(actual.status, tracker_pb2.ApprovalStatus.APPROVED)
1112 self.assertEqual(actual.setter_id, 111)
1113 self.assertEqual(actual.set_on, 1234)
1114 self.assertEqual(actual.subfield_vals_add, [added_fv])
1115 self.assertEqual(actual.subfield_vals_remove, [removed_fv])
1116 self.assertEqual(actual.subfields_clear, clear_fvs)
1117 self.assertEqual(actual.labels_add, labels_add)
1118 self.assertEqual(actual.labels_remove, labels_remove)
1119
1120 def testMakeApprovalDelta_WithNones(self):
1121 added_fv = tracker_bizobj.MakeFieldValue(
1122 1, None, 'added str', None, None, None, False)
1123 removed_fv = tracker_bizobj.MakeFieldValue(
1124 1, None, 'removed str', None, None, None, False)
1125 clear_fields = [2]
1126 labels_add = ['ittly-bittly', 'piggly-wiggly']
1127 labels_remove = ['golly-goops', 'whoopsie']
1128 actual = tracker_bizobj.MakeApprovalDelta(
1129 None, 111, [222], [],
1130 [added_fv], [removed_fv], clear_fields,
1131 labels_add, labels_remove)
1132 self.assertIsNone(actual.status)
1133 self.assertIsNone(actual.setter_id)
1134 self.assertIsNone(actual.set_on)
1135
1136 def testMakeIssueDelta_AllSpecified(self):
1137 added_fv = tracker_bizobj.MakeFieldValue(
1138 1, None, 'added str', None, None, None, False)
1139 removed_fv = tracker_bizobj.MakeFieldValue(
1140 1, None, 'removed str', None, None, None, False)
1141 actual = tracker_bizobj.MakeIssueDelta(
1142 'New', 111, [222], [333], [1], [2],
1143 ['AddedLabel'], ['RemovedLabel'], [added_fv], [removed_fv],
1144 [3], [78901], [78902], [78903], [78904], 78905,
1145 'New summary',
1146 ext_blocked_on_add=['b/123', 'b/234'],
1147 ext_blocked_on_remove=['b/345', 'b/456'],
1148 ext_blocking_add=['b/567', 'b/678'],
1149 ext_blocking_remove=['b/789', 'b/890'])
1150 self.assertEqual('New', actual.status)
1151 self.assertEqual(111, actual.owner_id)
1152 self.assertEqual([222], actual.cc_ids_add)
1153 self.assertEqual([333], actual.cc_ids_remove)
1154 self.assertEqual([1], actual.comp_ids_add)
1155 self.assertEqual([2], actual.comp_ids_remove)
1156 self.assertEqual(['AddedLabel'], actual.labels_add)
1157 self.assertEqual(['RemovedLabel'], actual.labels_remove)
1158 self.assertEqual([added_fv], actual.field_vals_add)
1159 self.assertEqual([removed_fv], actual.field_vals_remove)
1160 self.assertEqual([3], actual.fields_clear)
1161 self.assertEqual([78901], actual.blocked_on_add)
1162 self.assertEqual([78902], actual.blocked_on_remove)
1163 self.assertEqual([78903], actual.blocking_add)
1164 self.assertEqual([78904], actual.blocking_remove)
1165 self.assertEqual(78905, actual.merged_into)
1166 self.assertEqual('New summary', actual.summary)
1167 self.assertEqual(['b/123', 'b/234'], actual.ext_blocked_on_add)
1168 self.assertEqual(['b/345', 'b/456'], actual.ext_blocked_on_remove)
1169 self.assertEqual(['b/567', 'b/678'], actual.ext_blocking_add)
1170 self.assertEqual(['b/789', 'b/890'], actual.ext_blocking_remove)
1171
1172 def testMakeIssueDelta_WithNones(self):
1173 """None for status, owner_id, or summary does not set a value."""
1174 actual = tracker_bizobj.MakeIssueDelta(
1175 None, None, [], [], [], [],
1176 [], [], [], [],
1177 [], [], [], [], [], None,
1178 None)
1179 self.assertIsNone(actual.status)
1180 self.assertIsNone(actual.owner_id)
1181 self.assertIsNone(actual.merged_into)
1182 self.assertIsNone(actual.summary)
1183
1184 def testApplyLabelChanges_RemoveAndAdd(self):
1185 issue = tracker_pb2.Issue(
1186 labels=['tobe-removed', 'tobe-notremoved', 'tobe-removed-2'])
1187 amendment = tracker_bizobj.ApplyLabelChanges(
1188 issue, self.config,
1189 [u'tobe-added', 'to:be-added-2'],
1190 [u'tobe-removed', u'to:be-removed-2'])
1191 self.assertEqual(amendment, tracker_bizobj.MakeLabelsAmendment(
1192 ['tobe-added', 'tobe-added-2'], ['tobe-removed', 'tobe-removed-2']))
1193
1194 def testApplyLabelChanges_RemoveInvalidLabel(self):
1195 issue = tracker_pb2.Issue(labels=[])
1196 amendment = tracker_bizobj.ApplyLabelChanges(
1197 issue, self.config, [], [u'lost-car'])
1198 self.assertIsNone(amendment)
1199
1200 def testApplyLabelChanges_NoChangesAfterMerge(self):
1201 issue = tracker_pb2.Issue(labels=['lost-car'])
1202 amendment = tracker_bizobj.ApplyLabelChanges(
1203 issue, self.config, [u'lost-car'], [])
1204 self.assertIsNone(amendment)
1205
1206 def testApplyLabelChanges_Empty(self):
1207 issue = tracker_pb2.Issue(labels=[])
1208 amendment = tracker_bizobj.ApplyLabelChanges(issue, self.config, [], [])
1209 self.assertIsNone(amendment)
1210
1211 def testApplyFieldValueChanges(self):
1212 self.config.field_defs = [
1213 tracker_pb2.FieldDef(
1214 field_id=1, project_id=789, field_name='EstDays',
1215 field_type=tracker_pb2.FieldTypes.INT_TYPE),
1216 tracker_pb2.FieldDef(
1217 field_id=2, project_id=789, field_name='SleepHrs',
1218 field_type=tracker_pb2.FieldTypes.INT_TYPE, is_phase_field=True),
1219 tracker_pb2.FieldDef(
1220 field_id=3, project_id=789, field_name='Chickens',
1221 field_type=tracker_pb2.FieldTypes.STR_TYPE, is_phase_field=True,
1222 is_multivalued=True),
1223 ]
1224 original_keep = [
1225 tracker_pb2.FieldValue(field_id=3, str_value='bok', phase_id=45)]
1226 original_replace = [
1227 tracker_pb2.FieldValue(field_id=1, int_value=72),
1228 tracker_pb2.FieldValue(field_id=2, int_value=88, phase_id=44)]
1229 original_remove = [
1230 tracker_pb2.FieldValue(field_id=3, str_value='removedbok', phase_id=45),
1231 ]
1232 issue = tracker_pb2.Issue(
1233 phases=[
1234 tracker_pb2.Phase(phase_id=45, name='high-school'),
1235 tracker_pb2.Phase(phase_id=44, name='college')])
1236 issue.field_values = original_keep + original_replace + original_remove
1237
1238 fvs_add_ignore = [
1239 tracker_pb2.FieldValue(field_id=3, str_value='egg', phase_id=42)]
1240 fvs_add = [
1241 tracker_pb2.FieldValue(field_id=1, int_value=73), # replace
1242 tracker_pb2.FieldValue(field_id=2, int_value=99, phase_id=44), #replace
1243 tracker_pb2.FieldValue(field_id=2, int_value=100, phase_id=45), # added
1244 # added
1245 tracker_pb2.FieldValue(field_id=3, str_value='rooster', phase_id=45),
1246 ]
1247 fvs_remove = original_remove
1248 fields_clear = []
1249 amendments = tracker_bizobj.ApplyFieldValueChanges(
1250 issue, self.config, fvs_add+fvs_add_ignore, fvs_remove, fields_clear)
1251
1252 self.assertEqual(
1253 amendments,
1254 [tracker_bizobj.MakeFieldAmendment(1, self.config, [73]),
1255 tracker_bizobj.MakeFieldAmendment(
1256 2, self.config, [99], phase_name='college'),
1257 tracker_bizobj.MakeFieldAmendment(
1258 2, self.config, [100], phase_name='high-school'),
1259 tracker_bizobj.MakeFieldAmendment(
1260 3, self.config, ['rooster'], old_values=['removedbok'],
1261 phase_name='high-school')])
1262 self.assertEqual(issue.field_values, original_keep + fvs_add)
1263
1264 def testApplyIssueDelta_NoChange(self):
1265 """A delta with no change should change nothing."""
1266 issue = tracker_pb2.Issue(
1267 status='New', owner_id=111, cc_ids=[222], labels=['a', 'b'],
1268 component_ids=[1], blocked_on_iids=[78902], blocking_iids=[78903],
1269 merged_into=78904, summary='Sum')
1270 delta = tracker_pb2.IssueDelta()
1271
1272 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1273 self.cnxn, self.services.issue, issue, delta, self.config)
1274
1275 self.assertEqual('New', issue.status)
1276 self.assertEqual(111, issue.owner_id)
1277 self.assertEqual([222], issue.cc_ids)
1278 self.assertEqual(['a', 'b'], issue.labels)
1279 self.assertEqual([1], issue.component_ids)
1280 self.assertEqual([78902], issue.blocked_on_iids)
1281 self.assertEqual([78903], issue.blocking_iids)
1282 self.assertEqual(78904, issue.merged_into)
1283 self.assertEqual('Sum', issue.summary)
1284
1285 self.assertEqual(0, len(amendments))
1286 self.assertEqual(0, len(impacted_iids))
1287
1288 def testApplyIssueDelta_BuiltInFields(self):
1289 """A delta can change built-in fields."""
1290 ref_issue_70 = fake.MakeTestIssue(
1291 789, 70, 'Something that must be done before', 'New', 111)
1292 self.services.issue.TestAddIssue(ref_issue_70)
1293 ref_issue_71 = fake.MakeTestIssue(
1294 789, 71, 'Something that can only be done after', 'New', 111)
1295 self.services.issue.TestAddIssue(ref_issue_71)
1296 ref_issue_72 = fake.MakeTestIssue(
1297 789, 72, 'Something that seems the same', 'New', 111)
1298 self.services.issue.TestAddIssue(ref_issue_72)
1299 ref_issue_73 = fake.MakeTestIssue(
1300 789, 73, 'Something that used to seem the same', 'New', 111)
1301 self.services.issue.TestAddIssue(ref_issue_73)
1302 issue = tracker_pb2.Issue(
1303 status='New', owner_id=111, cc_ids=[222], labels=['a', 'b'],
1304 component_ids=[1], blocked_on_iids=[78902], blocking_iids=[78903],
1305 merged_into=ref_issue_73.issue_id, summary='Sum')
1306 delta = tracker_pb2.IssueDelta(
1307 status='Duplicate', owner_id=999, cc_ids_add=[333, 444],
1308 comp_ids_add=[2], labels_add=['c', 'd'],
1309 blocked_on_add=[ref_issue_70.issue_id],
1310 blocking_add=[ref_issue_71.issue_id],
1311 merged_into=ref_issue_72.issue_id, summary='New summary')
1312
1313 actual_amendments, actual_impacted_iids = tracker_bizobj.ApplyIssueDelta(
1314 self.cnxn, self.services.issue, issue, delta, self.config)
1315
1316 self.assertEqual('Duplicate', issue.status)
1317 self.assertEqual(999, issue.owner_id)
1318 self.assertEqual([222, 333, 444], issue.cc_ids)
1319 self.assertEqual([1, 2], issue.component_ids)
1320 self.assertEqual(['a', 'b', 'c', 'd'], issue.labels)
1321 self.assertEqual([78902, ref_issue_70.issue_id], issue.blocked_on_iids)
1322 self.assertEqual([78903, ref_issue_71.issue_id], issue.blocking_iids)
1323 self.assertEqual(ref_issue_72.issue_id, issue.merged_into)
1324 self.assertEqual('New summary', issue.summary)
1325
1326 self.assertEqual(
1327 [tracker_bizobj.MakeStatusAmendment('Duplicate', 'New'),
1328 tracker_bizobj.MakeOwnerAmendment(999, 111),
1329 tracker_bizobj.MakeCcAmendment([333, 444], []),
1330 tracker_bizobj.MakeComponentsAmendment([2], [], self.config),
1331 tracker_bizobj.MakeLabelsAmendment(['c', 'd'], []),
1332 tracker_bizobj.MakeBlockedOnAmendment([(None, 70)], []),
1333 tracker_bizobj.MakeBlockingAmendment([(None, 71)], []),
1334 tracker_bizobj.MakeMergedIntoAmendment([(None, 72)], [(None, 73)]),
1335 tracker_bizobj.MakeSummaryAmendment('New summary', 'Sum'),
1336 ],
1337 actual_amendments)
1338 self.assertEqual(
1339 set([ref_issue_70.issue_id, ref_issue_71.issue_id,
1340 ref_issue_72.issue_id, ref_issue_73.issue_id]),
1341 actual_impacted_iids)
1342
1343 def testApplyIssueDelta_ReferrencedIssueNotFound(self):
1344 """This part of the code copes with missing issues."""
1345 issue = tracker_pb2.Issue(
1346 status='New', owner_id=111, cc_ids=[222], labels=['a', 'b'],
1347 component_ids=[1], blocked_on_iids=[78902], blocking_iids=[78903],
1348 merged_into=78904, summary='Sum')
1349 delta = tracker_pb2.IssueDelta(
1350 blocked_on_add=[78905], blocked_on_remove=[78902],
1351 blocking_add=[78906], blocking_remove=[78903],
1352 merged_into=78907)
1353
1354 actual_amendments, actual_impacted_iids = tracker_bizobj.ApplyIssueDelta(
1355 self.cnxn, self.services.issue, issue, delta, self.config)
1356
1357 self.assertEqual([78905], issue.blocked_on_iids)
1358 self.assertEqual([78906], issue.blocking_iids)
1359 self.assertEqual(78907, issue.merged_into)
1360
1361 self.assertEqual(
1362 [tracker_bizobj.MakeBlockedOnAmendment([], []),
1363 tracker_bizobj.MakeBlockingAmendment([], []),
1364 tracker_bizobj.MakeMergedIntoAmendment([], []),
1365 ],
1366 actual_amendments)
1367 self.assertEqual(
1368 set([78902, 78903, 78905, 78906]),
1369 actual_impacted_iids)
1370
1371 def testApplyIssueDelta_CustomPhaseFields(self):
1372 """A delta can add, remove, or clear custom phase fields."""
1373 fd_a = tracker_pb2.FieldDef(
1374 field_id=1, project_id=789, field_name='a',
1375 field_type=tracker_pb2.FieldTypes.INT_TYPE,
1376 is_multivalued=True, is_phase_field=True)
1377 fd_b = tracker_pb2.FieldDef(
1378 field_id=2, project_id=789, field_name='b',
1379 field_type=tracker_pb2.FieldTypes.INT_TYPE,
1380 is_phase_field=True)
1381 fd_c = tracker_pb2.FieldDef(
1382 field_id=3, project_id=789, field_name='c',
1383 field_type=tracker_pb2.FieldTypes.INT_TYPE, is_phase_field=True)
1384 self.config.field_defs = [fd_a, fd_b, fd_c]
1385 fv_a1_p1 = tracker_pb2.FieldValue(
1386 field_id=1, int_value=1, phase_id=1) # fv
1387 fv_a2_p1 = tracker_pb2.FieldValue(
1388 field_id=1, int_value=2, phase_id=1) # add
1389 fv_a3_p1 = tracker_pb2.FieldValue(
1390 field_id=1, int_value=3, phase_id=1) # add
1391 fv_b1_p1 = tracker_pb2.FieldValue(
1392 field_id=2, int_value=1, phase_id=1) # add
1393 fv_c2_p1 = tracker_pb2.FieldValue(
1394 field_id=3, int_value=2, phase_id=1) # clear
1395
1396 fv_a2_p2 = tracker_pb2.FieldValue(
1397 field_id=1, int_value=2, phase_id=2) # add
1398 fv_b1_p2 = tracker_pb2.FieldValue(
1399 field_id=2, int_value=1, phase_id=2) # fv remove
1400 fv_c1_p2 = tracker_pb2.FieldValue(
1401 field_id=3, int_value=1, phase_id=2) # clear
1402
1403 issue = tracker_pb2.Issue(
1404 status='New', owner_id=111, summary='Sum',
1405 field_values=[fv_a1_p1, fv_c2_p1, fv_b1_p2, fv_c1_p2])
1406 issue.phases = [
1407 tracker_pb2.Phase(phase_id=1, name='Phase-1'),
1408 tracker_pb2.Phase(phase_id=2, name='Phase-2')]
1409
1410 delta = tracker_pb2.IssueDelta(
1411 field_vals_add=[fv_a2_p1, fv_a3_p1, fv_b1_p1, fv_a2_p2],
1412 field_vals_remove=[fv_b1_p2], fields_clear=[3])
1413
1414 actual_amendments, actual_impacted_iids = tracker_bizobj.ApplyIssueDelta(
1415 self.cnxn, self.services.issue, issue, delta, self.config)
1416 self.assertEqual(
1417 [tracker_bizobj.MakeFieldAmendment(
1418 1, self.config, ['2', '3'], [], phase_name='Phase-1'),
1419 tracker_bizobj.MakeFieldAmendment(
1420 1, self.config, ['2'], [], phase_name='Phase-2'),
1421 tracker_bizobj.MakeFieldAmendment(
1422 2, self.config, ['1'], [], phase_name='Phase-1'),
1423 tracker_bizobj.MakeFieldAmendment(
1424 2, self.config, [], ['1'], phase_name='Phase-2'),
1425 tracker_bizobj.MakeFieldClearedAmendment(3, self.config)],
1426 actual_amendments)
1427 self.assertEqual(set(), actual_impacted_iids)
1428
1429 def testApplyIssueDelta_CustomFields(self):
1430 """A delta can add, remove, or clear custom fields."""
1431 fd_a = tracker_pb2.FieldDef(
1432 field_id=1, project_id=789, field_name='a',
1433 field_type=tracker_pb2.FieldTypes.INT_TYPE,
1434 is_multivalued=True)
1435 fd_b = tracker_pb2.FieldDef(
1436 field_id=2, project_id=789, field_name='b',
1437 field_type=tracker_pb2.FieldTypes.INT_TYPE)
1438 fd_c = tracker_pb2.FieldDef(
1439 field_id=3, project_id=789, field_name='c',
1440 field_type=tracker_pb2.FieldTypes.INT_TYPE)
1441 fd_d = tracker_pb2.FieldDef(
1442 field_id=4, project_id=789, field_name='d',
1443 field_type=tracker_pb2.FieldTypes.ENUM_TYPE)
1444 self.config.field_defs = [fd_a, fd_b, fd_c, fd_d]
1445 fv_a1 = tracker_pb2.FieldValue(field_id=1, int_value=1)
1446 fv_a2 = tracker_pb2.FieldValue(field_id=1, int_value=2)
1447 fv_b1 = tracker_pb2.FieldValue(field_id=2, int_value=1)
1448 fv_c1 = tracker_pb2.FieldValue(field_id=3, int_value=1)
1449 issue = tracker_pb2.Issue(
1450 status='New', owner_id=111, labels=['d-val', 'Hot'], summary='Sum',
1451 field_values=[fv_a1, fv_b1, fv_c1])
1452 delta = tracker_pb2.IssueDelta(
1453 field_vals_add=[fv_a2], field_vals_remove=[fv_b1], fields_clear=[3, 4])
1454
1455 actual_amendments, actual_impacted_iids = tracker_bizobj.ApplyIssueDelta(
1456 self.cnxn, self.services.issue, issue, delta, self.config)
1457
1458 self.assertEqual([fv_a1, fv_a2], issue.field_values)
1459 self.assertEqual(['Hot'], issue.labels)
1460
1461 self.assertEqual(
1462 [tracker_bizobj.MakeFieldAmendment(1, self.config, ['2'], []),
1463 tracker_bizobj.MakeFieldAmendment(2, self.config, [], ['1']),
1464 tracker_bizobj.MakeFieldClearedAmendment(3, self.config),
1465 tracker_bizobj.MakeFieldClearedAmendment(4, self.config),
1466 ],
1467 actual_amendments)
1468 self.assertEqual(set(), actual_impacted_iids)
1469
1470 def testApplyIssueDelta_ExternalRefs(self):
1471 """Only applies valid issue refs from a delta."""
1472 issue = tracker_pb2.Issue(
1473 status='New', owner_id=111, cc_ids=[222], labels=['a', 'b'],
1474 component_ids=[1], blocked_on_iids=[78902], blocking_iids=[78903],
1475 merged_into=78904, summary='Sum',
1476 dangling_blocked_on_refs=[
1477 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/345'),
1478 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111')],
1479 dangling_blocking_refs=[
1480 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/789'),
1481 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222')])
1482 delta = tracker_pb2.IssueDelta(
1483 # Add one valid, one invalid, and another valid.
1484 ext_blocked_on_add=['b/123', 'b123', 'b/234'],
1485 # Remove one valid, one invalid, and one that does not exist.
1486 ext_blocked_on_remove=['b/345', 'b', 'b/456'],
1487 # Add one valid, one invalid, and another valid.
1488 ext_blocking_add=['b/567', 'b//123', 'b/678'],
1489 # Remove one valid, one invalid, and one that does not exist.
1490 ext_blocking_remove=['b/789', 'b/123/123', 'b/890'])
1491
1492 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1493 self.cnxn, self.services.issue, issue, delta, self.config)
1494
1495 # Test amendments.
1496 self.assertEqual(2, len(amendments))
1497 self.assertEqual(tracker_pb2.FieldID.BLOCKEDON, amendments[0].field)
1498 self.assertEqual('-b/345 b/123 b/234', amendments[0].newvalue)
1499 self.assertEqual(tracker_pb2.FieldID.BLOCKING, amendments[1].field)
1500 self.assertEqual('-b/789 b/567 b/678', amendments[1].newvalue)
1501
1502 self.assertEqual(0, len(impacted_iids))
1503
1504 # Issue refs are applied correctly and alphabetized.
1505 self.assertEqual([
1506 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111'),
1507 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/123'),
1508 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/234'),
1509 ], issue.dangling_blocked_on_refs)
1510 self.assertEqual([
1511 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222'),
1512 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/567'),
1513 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/678'),
1514 ], issue.dangling_blocking_refs)
1515
1516 def testApplyIssueDelta_AddAndRemoveExtRef(self):
1517 """Only applies valid issue refs from a delta."""
1518 issue = tracker_pb2.Issue(
1519 status='New',
1520 summary='Sum',
1521 dangling_blocked_on_refs=[
1522 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111')
1523 ],
1524 dangling_blocking_refs=[
1525 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222')
1526 ])
1527 delta = tracker_pb2.IssueDelta(
1528 ext_blocked_on_add=['b/123'],
1529 ext_blocked_on_remove=['b/123'],
1530 ext_blocking_add=['b/456'],
1531 ext_blocking_remove=['b/456'])
1532
1533 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1534 self.cnxn, self.services.issue, issue, delta, self.config)
1535
1536 # Nothing changed.
1537 self.assertEqual(0, len(amendments))
1538 self.assertEqual(0, len(impacted_iids))
1539
1540 self.assertEqual(
1541 [tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111')],
1542 issue.dangling_blocked_on_refs)
1543 self.assertEqual(
1544 [tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222')],
1545 issue.dangling_blocking_refs)
1546
1547 def testApplyIssueDelta_OnlyInvalidExternalRefs(self):
1548 """Only applies valid issue refs from a delta."""
1549 issue = tracker_pb2.Issue(
1550 status='New',
1551 summary='Sum',
1552 dangling_blocked_on_refs=[
1553 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111')
1554 ],
1555 dangling_blocking_refs=[
1556 tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222')
1557 ])
1558 delta = tracker_pb2.IssueDelta(
1559 # Add one invalid and one that already exists.
1560 ext_blocked_on_add=['b123', 'b/111'],
1561 # Remove one invalid, and one that does not exist.
1562 ext_blocked_on_remove=['b', 'b/456'],
1563 # Add one invalid and one that already exists.
1564 ext_blocking_add=['b//123', 'b/222'],
1565 # Remove one invalid, and one that does not exist.
1566 ext_blocking_remove=['b/123/123', 'b/890'])
1567
1568 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1569 self.cnxn, self.services.issue, issue, delta, self.config)
1570
1571 # Nothing changed.
1572 self.assertEqual(0, len(amendments))
1573 self.assertEqual(0, len(impacted_iids))
1574
1575 self.assertEqual(
1576 [tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/111')],
1577 issue.dangling_blocked_on_refs)
1578 self.assertEqual(
1579 [tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/222')],
1580 issue.dangling_blocking_refs)
1581
1582 def testApplyIssueDelta_MergedIntoExternal(self):
1583 """ApplyIssueDelta applies valid mergedinto refs."""
1584 issue = tracker_pb2.Issue(status='New', owner_id=111)
1585 delta = tracker_pb2.IssueDelta(merged_into_external='b/5678')
1586 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1587 self.cnxn, self.services.issue, issue, delta, self.config)
1588
1589 # Test amendments.
1590 self.assertEqual(1, len(amendments))
1591 self.assertEqual(tracker_pb2.FieldID.MERGEDINTO, amendments[0].field)
1592 self.assertEqual('b/5678', amendments[0].newvalue)
1593
1594 self.assertEqual(0, len(impacted_iids))
1595
1596 # Issue refs are applied correctly and alphabetized.
1597 self.assertEqual('b/5678', issue.merged_into_external)
1598
1599 def testApplyIssueDelta_MergedIntoExternalInvalid(self):
1600 """ApplyIssueDelta does not accept invalid mergedinto refs."""
1601 issue = tracker_pb2.Issue(status='New', owner_id=111)
1602 delta = tracker_pb2.IssueDelta(merged_into_external='a/5678')
1603 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1604 self.cnxn, self.services.issue, issue, delta, self.config)
1605
1606 # No change.
1607 self.assertEqual(0, len(amendments))
1608 self.assertEqual(0, len(impacted_iids))
1609 self.assertEqual(None, issue.merged_into_external)
1610
1611 def testApplyIssueDelta_MergedIntoFromInternalToExternal(self):
1612 """ApplyIssueDelta updates from an internal to an external ref."""
1613 self.services.issue.TestAddIssue(fake.MakeTestIssue(1, 2, 'Summary',
1614 'New', 111, issue_id=6789))
1615 issue = tracker_pb2.Issue(status='New', owner_id=111, merged_into=6789)
1616 delta = tracker_pb2.IssueDelta(merged_into_external='b/5678')
1617 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1618 self.cnxn, self.services.issue, issue, delta, self.config)
1619
1620 # Test amendments.
1621 self.assertEqual(1, len(amendments))
1622 self.assertEqual(tracker_pb2.FieldID.MERGEDINTO, amendments[0].field)
1623 self.assertEqual('-2 b/5678', amendments[0].newvalue)
1624 self.assertEqual(set([6789]), impacted_iids)
1625 self.assertEqual(0, issue.merged_into)
1626 self.assertEqual('b/5678', issue.merged_into_external)
1627
1628 def testApplyIssueDelta_MergedIntoFromExternalToInternal(self):
1629 """ApplyIssueDelta updates from an external to an internalref."""
1630 self.services.issue.TestAddIssue(fake.MakeTestIssue(1, 2, 'Summary',
1631 'New', 111, issue_id=6789))
1632 issue = tracker_pb2.Issue(status='New', owner_id=111,
1633 merged_into_external='b/5678')
1634 delta = tracker_pb2.IssueDelta(merged_into=6789)
1635 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1636 self.cnxn, self.services.issue, issue, delta, self.config)
1637
1638 # Test amendments.
1639 self.assertEqual(1, len(amendments))
1640 self.assertEqual(tracker_pb2.FieldID.MERGEDINTO, amendments[0].field)
1641 self.assertEqual('-b/5678 2', amendments[0].newvalue)
1642 self.assertEqual(set([6789]), impacted_iids)
1643 self.assertEqual(6789, issue.merged_into)
1644 self.assertEqual(None, issue.merged_into_external)
1645
1646 def testApplyIssueDelta_MergedIntoFromExternalToExternal(self):
1647 """ApplyIssueDelta updates from an external to another external ref."""
1648 issue = tracker_pb2.Issue(
1649 status='New', owner_id=111, merged_into_external='b/1')
1650 delta = tracker_pb2.IssueDelta(merged_into_external='b/5678')
1651 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1652 self.cnxn, self.services.issue, issue, delta, self.config)
1653
1654 # Test amendments.
1655 self.assertEqual(1, len(amendments))
1656 self.assertEqual(tracker_pb2.FieldID.MERGEDINTO, amendments[0].field)
1657 self.assertEqual('-b/1 b/5678', amendments[0].newvalue)
1658 self.assertEqual(set(), impacted_iids)
1659 self.assertEqual(0, issue.merged_into)
1660 self.assertEqual('b/5678', issue.merged_into_external)
1661
1662 def testApplyIssueDelta_NoMergedIntoInternalAndExternal(self):
1663 """ApplyIssueDelta does not allow updating the internal and external
1664 merged_into fields at the same time.
1665 """
1666 issue = tracker_pb2.Issue(status='New', owner_id=111, merged_into=321)
1667 delta = tracker_pb2.IssueDelta(merged_into=543,
1668 merged_into_external='b/5678')
1669 with self.assertRaises(ValueError):
1670 tracker_bizobj.ApplyIssueDelta(self.cnxn, self.services.issue, issue,
1671 delta, self.config)
1672
1673 def testApplyIssueDelta_RemoveExistingMergedInto(self):
1674 self.services.issue.TestAddIssue(
1675 fake.MakeTestIssue(1, 2, 'Summary', 'New', 111, issue_id=6789))
1676 issue = tracker_pb2.Issue(status='New', owner_id=111, merged_into=6789)
1677 delta = tracker_pb2.IssueDelta(merged_into=0)
1678 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1679 self.cnxn, self.services.issue, issue, delta, self.config)
1680 self.assertEqual(impacted_iids, {6789})
1681 self.assertEqual(1, len(amendments))
1682 self.assertEqual(
1683 amendments[0],
1684 tracker_bizobj.MakeMergedIntoAmendment(
1685 [], [(issue.project_name, 2)],
1686 default_project_name=issue.project_name))
1687 self.assertEqual(issue.merged_into, 0)
1688
1689 def testApplyIssueDelta_RemoveExternalMergedInto(self):
1690 issue = tracker_pb2.Issue(
1691 status='New', owner_id=111, merged_into_external='b/123')
1692 delta = tracker_pb2.IssueDelta(merged_into_external='')
1693 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1694 self.cnxn, self.services.issue, issue, delta, self.config)
1695 self.assertEqual(impacted_iids, set())
1696 self.assertEqual(1, len(amendments))
1697 self.assertEqual(
1698 amendments[0],
1699 tracker_bizobj.MakeMergedIntoAmendment(
1700 [], [tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/123')]))
1701 self.assertEqual(issue.merged_into_external, '')
1702
1703 def testApplyIssueDelta_RemoveMergedIntoNoop(self):
1704 issue = tracker_pb2.Issue(
1705 status='New', owner_id=111, merged_into_external='b/123')
1706 delta = tracker_pb2.IssueDelta(merged_into=0)
1707 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1708 self.cnxn, self.services.issue, issue, delta, self.config)
1709 self.assertEqual(impacted_iids, set())
1710 self.assertEqual(0, len(amendments))
1711 # A noop request to remove merged_into, should not affect the existing
1712 # external value.
1713 self.assertIsNone(issue.merged_into)
1714 self.assertEqual(issue.merged_into_external, 'b/123')
1715
1716 def testApplyIssueDelta_RemoveExternalMergedIntoNoop(self):
1717 self.services.issue.TestAddIssue(
1718 fake.MakeTestIssue(1, 2, 'Summary', 'New', 111, issue_id=6789))
1719 issue = tracker_pb2.Issue(status='New', owner_id=111, merged_into=6789)
1720 delta = tracker_pb2.IssueDelta(merged_into_external='')
1721 amendments, impacted_iids = tracker_bizobj.ApplyIssueDelta(
1722 self.cnxn, self.services.issue, issue, delta, self.config)
1723 self.assertEqual(impacted_iids, set())
1724 self.assertEqual(len(amendments), 0)
1725 # A noop request to remove merged_into_external, should not affect the
1726 # existing internal merged_into value.
1727 self.assertIsNone(issue.merged_into_external)
1728 self.assertEqual(issue.merged_into, 6789)
1729
1730 def testApplyIssueBlockRelationChanges(self):
1731 """We can apply blocking and blocked_on relation changes to an issue."""
1732
1733 blocked_on = fake.MakeTestIssue(
1734 789, 2, 'Something that must be done before', 'New', 111,
1735 project_name='proj')
1736 self.services.issue.TestAddIssue(blocked_on)
1737 blocking = fake.MakeTestIssue(
1738 789, 3, 'Something that must be done after', 'New', 111,
1739 project_name='proj')
1740 self.services.issue.TestAddIssue(blocking)
1741
1742 issue = tracker_pb2.Issue(
1743 project_name='chicken',
1744 blocked_on_iids=[blocked_on.issue_id, 78904],
1745 blocking_iids=[blocking.issue_id, 78905])
1746 blocked_on_add = fake.MakeTestIssue(
1747 789, 6, 'Something that must be done before', 'New', 111,
1748 project_name='chicken')
1749 self.services.issue.TestAddIssue(blocked_on_add)
1750 blocking_add = fake.MakeTestIssue(
1751 789, 7, 'Something that must be done after', 'New', 111,
1752 project_name='chicken')
1753 self.services.issue.TestAddIssue(blocking_add)
1754
1755 (actual_amendments, actual_impacted_iids
1756 ) = tracker_bizobj.ApplyIssueBlockRelationChanges(
1757 self.cnxn,
1758 issue,
1759 # 78904 ref already exists can't be added, shuold ignore.
1760 # 78404 ref does not exist, can't be removed, should ignore.
1761 # blocked_on is ignored in the add list, but honored in the remove.
1762 [blocked_on_add.issue_id, 78904, blocked_on.issue_id],
1763 [78404, blocked_on.issue_id],
1764 # 78905 ref already exists, can't be added, should ignore.
1765 # 79404 ref does not exist in issue, can't be removed, should ignore.
1766 # blocking_add is ignored in the remove list, but honored in the add.
1767 [blocking_add.issue_id, 78905],
1768 [79404, blocking.issue_id, blocking_add.issue_id],
1769 self.services.issue)
1770
1771 expected_amendments = [
1772 tracker_bizobj.MakeBlockedOnAmendment(
1773 [('chicken', blocked_on_add.local_id)],
1774 [('proj', blocked_on.local_id)],
1775 default_project_name=issue.project_name),
1776 tracker_bizobj.MakeBlockingAmendment(
1777 [('chicken', blocking_add.local_id)], [('proj', blocking.local_id)],
1778 default_project_name=issue.project_name)
1779 ]
1780 self.assertEqual(actual_amendments, expected_amendments)
1781 self.assertItemsEqual(
1782 actual_impacted_iids, [
1783 blocked_on_add.issue_id, blocking_add.issue_id, blocked_on.issue_id,
1784 blocking.issue_id
1785 ])
1786 self.assertEqual(issue.blocked_on_iids, [78904, blocked_on_add.issue_id])
1787 self.assertEqual(issue.blocking_iids, [78905, blocking_add.issue_id])
1788
1789 def testApplyIssueBlockRelationChanges_Empty(self):
1790 """We can handle empty blocking and blocked_on relation changes."""
1791 issue = tracker_pb2.Issue(blocked_on_iids=[78901], blocking_iids=[78902])
1792 (actual_amendments,
1793 actual_impacted_iids) = tracker_bizobj.ApplyIssueBlockRelationChanges(
1794 self.cnxn, issue, [], [], [], [], self.services.issue)
1795
1796 self.assertEqual(actual_amendments, [])
1797 self.assertEqual(actual_impacted_iids, set())
1798 self.assertEqual(issue.blocked_on_iids, [78901])
1799 self.assertEqual(issue.blocking_iids, [78902])
1800
1801 def testMakeAmendment(self):
1802 amendment = tracker_bizobj.MakeAmendment(
1803 tracker_pb2.FieldID.STATUS, 'new', [111], [222])
1804 self.assertEqual(tracker_pb2.FieldID.STATUS, amendment.field)
1805 self.assertEqual('new', amendment.newvalue)
1806 self.assertEqual([111], amendment.added_user_ids)
1807 self.assertEqual([222], amendment.removed_user_ids)
1808
1809 def testPlusMinusString(self):
1810 self.assertEqual('', tracker_bizobj._PlusMinusString([], []))
1811 self.assertEqual('-a -b c d',
1812 tracker_bizobj._PlusMinusString(['c', 'd'], ['a', 'b']))
1813
1814 def testPlusMinusAmendment(self):
1815 amendment = tracker_bizobj._PlusMinusAmendment(
1816 tracker_pb2.FieldID.STATUS, ['add1', 'add2'], ['remove1'])
1817 self.assertEqual(tracker_pb2.FieldID.STATUS, amendment.field)
1818 self.assertEqual('-remove1 add1 add2', amendment.newvalue)
1819
1820 def testPlusMinusRefsAmendment(self):
1821 ref1 = (None, 1)
1822 ref2 = ('other-proj', 2)
1823 amendment = tracker_bizobj._PlusMinusRefsAmendment(
1824 tracker_pb2.FieldID.STATUS, [ref1], [ref2])
1825 self.assertEqual(tracker_pb2.FieldID.STATUS, amendment.field)
1826 self.assertEqual('-other-proj:2 1', amendment.newvalue)
1827
1828 def testMakeSummaryAmendment(self):
1829 amendment = tracker_bizobj.MakeSummaryAmendment('', None)
1830 self.assertEqual(tracker_pb2.FieldID.SUMMARY, amendment.field)
1831 self.assertEqual('', amendment.newvalue)
1832 self.assertEqual(None, amendment.oldvalue)
1833
1834 amendment = tracker_bizobj.MakeSummaryAmendment('new summary', '')
1835 self.assertEqual(tracker_pb2.FieldID.SUMMARY, amendment.field)
1836 self.assertEqual('new summary', amendment.newvalue)
1837 self.assertEqual('', amendment.oldvalue)
1838
1839 def testMakeStatusAmendment(self):
1840 amendment = tracker_bizobj.MakeStatusAmendment('', None)
1841 self.assertEqual(tracker_pb2.FieldID.STATUS, amendment.field)
1842 self.assertEqual('', amendment.newvalue)
1843 self.assertEqual(None, amendment.oldvalue)
1844
1845 amendment = tracker_bizobj.MakeStatusAmendment('New', '')
1846 self.assertEqual(tracker_pb2.FieldID.STATUS, amendment.field)
1847 self.assertEqual('New', amendment.newvalue)
1848 self.assertEqual('', amendment.oldvalue)
1849
1850 def testMakeOwnerAmendment(self):
1851 amendment = tracker_bizobj.MakeOwnerAmendment(111, 0)
1852 self.assertEqual(tracker_pb2.FieldID.OWNER, amendment.field)
1853 self.assertEqual('', amendment.newvalue)
1854 self.assertEqual([111], amendment.added_user_ids)
1855 self.assertEqual([0], amendment.removed_user_ids)
1856
1857 def testMakeCcAmendment(self):
1858 amendment = tracker_bizobj.MakeCcAmendment([111], [222])
1859 self.assertEqual(tracker_pb2.FieldID.CC, amendment.field)
1860 self.assertEqual('', amendment.newvalue)
1861 self.assertEqual([111], amendment.added_user_ids)
1862 self.assertEqual([222], amendment.removed_user_ids)
1863
1864 def testMakeLabelsAmendment(self):
1865 amendment = tracker_bizobj.MakeLabelsAmendment(['added1'], ['removed1'])
1866 self.assertEqual(tracker_pb2.FieldID.LABELS, amendment.field)
1867 self.assertEqual('-removed1 added1', amendment.newvalue)
1868
1869 def testDiffValueLists(self):
1870 added, removed = tracker_bizobj.DiffValueLists([], [])
1871 self.assertItemsEqual([], added)
1872 self.assertItemsEqual([], removed)
1873
1874 added, removed = tracker_bizobj.DiffValueLists([], None)
1875 self.assertItemsEqual([], added)
1876 self.assertItemsEqual([], removed)
1877
1878 added, removed = tracker_bizobj.DiffValueLists([1, 2], [])
1879 self.assertItemsEqual([1, 2], added)
1880 self.assertItemsEqual([], removed)
1881
1882 added, removed = tracker_bizobj.DiffValueLists([], [8, 9])
1883 self.assertItemsEqual([], added)
1884 self.assertItemsEqual([8, 9], removed)
1885
1886 added, removed = tracker_bizobj.DiffValueLists([1, 2], [8, 9])
1887 self.assertItemsEqual([1, 2], added)
1888 self.assertItemsEqual([8, 9], removed)
1889
1890 added, removed = tracker_bizobj.DiffValueLists([1, 2, 5, 6], [5, 6, 8, 9])
1891 self.assertItemsEqual([1, 2], added)
1892 self.assertItemsEqual([8, 9], removed)
1893
1894 added, removed = tracker_bizobj.DiffValueLists([5, 6], [5, 6, 8, 9])
1895 self.assertItemsEqual([], added)
1896 self.assertItemsEqual([8, 9], removed)
1897
1898 added, removed = tracker_bizobj.DiffValueLists([1, 2, 5, 6], [5, 6])
1899 self.assertItemsEqual([1, 2], added)
1900 self.assertItemsEqual([], removed)
1901
1902 added, removed = tracker_bizobj.DiffValueLists(
1903 [1, 2, 2, 5, 6], [5, 6, 8, 9])
1904 self.assertItemsEqual([1, 2, 2], added)
1905 self.assertItemsEqual([8, 9], removed)
1906
1907 added, removed = tracker_bizobj.DiffValueLists(
1908 [1, 2, 5, 6], [5, 6, 8, 8, 9])
1909 self.assertItemsEqual([1, 2], added)
1910 self.assertItemsEqual([8, 8, 9], removed)
1911
1912 def testMakeFieldAmendment_NoSuchFieldDef(self):
1913 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1914 with self.assertRaises(ValueError):
1915 tracker_bizobj.MakeFieldAmendment(1, config, ['Large'], ['Small'])
1916
1917 def testMakeFieldAmendment_MultiValued(self):
1918 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1919 fd = tracker_pb2.FieldDef(
1920 field_id=1, field_name='Days', is_multivalued=True)
1921 config.field_defs.append(fd)
1922 self.assertEqual(
1923 tracker_bizobj.MakeAmendment(
1924 tracker_pb2.FieldID.CUSTOM, '-Mon Tue Wed', [], [], 'Days'),
1925 tracker_bizobj.MakeFieldAmendment(1, config, ['Tue', 'Wed'], ['Mon']))
1926 self.assertEqual(
1927 tracker_bizobj.MakeAmendment(
1928 tracker_pb2.FieldID.CUSTOM, '-Mon', [], [], 'Days'),
1929 tracker_bizobj.MakeFieldAmendment(1, config, [], ['Mon']))
1930
1931 def testMakeFieldAmendment_MultiValuedUser(self):
1932 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1933 fd = tracker_pb2.FieldDef(
1934 field_id=1, field_name='Friends', is_multivalued=True,
1935 field_type=tracker_pb2.FieldTypes.USER_TYPE)
1936 config.field_defs.append(fd)
1937 self.assertEqual(
1938 tracker_bizobj.MakeAmendment(
1939 tracker_pb2.FieldID.CUSTOM, '', [111], [222], 'Friends'),
1940 tracker_bizobj.MakeFieldAmendment(1, config, [111], [222]))
1941 self.assertEqual(
1942 tracker_bizobj.MakeAmendment(
1943 tracker_pb2.FieldID.CUSTOM, '', [], [222], 'Friends'),
1944 tracker_bizobj.MakeFieldAmendment(1, config, [], [222]))
1945
1946 def testMakeFieldAmendment_SingleValued(self):
1947 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1948 fd = tracker_pb2.FieldDef(field_id=1, field_name='Size')
1949 config.field_defs.append(fd)
1950 self.assertEqual(
1951 tracker_bizobj.MakeAmendment(
1952 tracker_pb2.FieldID.CUSTOM, 'Large', [], [], 'Size'),
1953 tracker_bizobj.MakeFieldAmendment(1, config, ['Large'], ['Small']))
1954 self.assertEqual(
1955 tracker_bizobj.MakeAmendment(
1956 tracker_pb2.FieldID.CUSTOM, '----', [], [], 'Size'),
1957 tracker_bizobj.MakeFieldAmendment(1, config, [], ['Small']))
1958
1959 def testMakeFieldAmendment_SingleValuedUser(self):
1960 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1961 fd = tracker_pb2.FieldDef(
1962 field_id=1, field_name='Friend',
1963 field_type=tracker_pb2.FieldTypes.USER_TYPE)
1964 config.field_defs.append(fd)
1965 self.assertEqual(
1966 tracker_bizobj.MakeAmendment(
1967 tracker_pb2.FieldID.CUSTOM, '', [111], [], 'Friend'),
1968 tracker_bizobj.MakeFieldAmendment(1, config, [111], [222]))
1969 self.assertEqual(
1970 tracker_bizobj.MakeAmendment(
1971 tracker_pb2.FieldID.CUSTOM, '', [], [], 'Friend'),
1972 tracker_bizobj.MakeFieldAmendment(1, config, [], [222]))
1973
1974 def testMakeFieldAmendment_PhaseField(self):
1975 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1976 fd = tracker_pb2.FieldDef(
1977 field_id=1, field_name='Friend',
1978 field_type=tracker_pb2.FieldTypes.USER_TYPE, is_phase_field=True)
1979 config.field_defs.append(fd)
1980 self.assertEqual(
1981 tracker_bizobj.MakeAmendment(
1982 tracker_pb2.FieldID.CUSTOM, '', [111], [], 'PhaseName-Friend'),
1983 tracker_bizobj.MakeFieldAmendment(
1984 1, config, [111], [222], phase_name='PhaseName'))
1985 self.assertEqual(
1986 tracker_bizobj.MakeAmendment(
1987 tracker_pb2.FieldID.CUSTOM, '', [], [], 'PhaseName-3-Friend'),
1988 tracker_bizobj.MakeFieldAmendment(
1989 1, config, [], [222], phase_name='PhaseName-3'))
1990
1991 def testMakeFieldClearedAmendment_FieldNotFound(self):
1992 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1993 with self.assertRaises(ValueError):
1994 tracker_bizobj.MakeFieldClearedAmendment(1, config)
1995
1996 def testMakeFieldClearedAmendment_Normal(self):
1997 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
1998 fd = tracker_pb2.FieldDef(field_id=1, field_name='Rabbit')
1999 config.field_defs.append(fd)
2000 self.assertEqual(
2001 tracker_bizobj.MakeAmendment(
2002 tracker_pb2.FieldID.CUSTOM, '----', [], [], 'Rabbit'),
2003 tracker_bizobj.MakeFieldClearedAmendment(1, config))
2004
2005 def testMakeApprovalStructureAmendment(self):
2006 actual_amendment = tracker_bizobj.MakeApprovalStructureAmendment(
2007 ['Chicken1', 'Chicken', 'Llama'], ['Cow', 'Chicken2', 'Llama'])
2008 amendment = tracker_bizobj.MakeAmendment(
2009 tracker_pb2.FieldID.CUSTOM, '-Cow -Chicken2 Chicken1 Chicken',
2010 [], [], 'Approvals')
2011 self.assertEqual(amendment, actual_amendment)
2012
2013 def testMakeApprovalStatusAmendment(self):
2014 actual_amendment = tracker_bizobj.MakeApprovalStatusAmendment(
2015 tracker_pb2.ApprovalStatus.APPROVED)
2016 amendment = tracker_pb2.Amendment(
2017 field=tracker_pb2.FieldID.CUSTOM, newvalue='approved',
2018 custom_field_name='Status')
2019 self.assertEqual(amendment, actual_amendment)
2020
2021 def testMakeApprovalApproversAmendment(self):
2022 actual_amendment = tracker_bizobj.MakeApprovalApproversAmendment(
2023 [222], [333])
2024 amendment = tracker_pb2.Amendment(
2025 field=tracker_pb2.FieldID.CUSTOM, newvalue='', added_user_ids=[222],
2026 removed_user_ids=[333], custom_field_name='Approvers')
2027 self.assertEqual(actual_amendment, amendment)
2028
2029 def testMakeComponentsAmendment_NoChange(self):
2030 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
2031 config.component_defs = [
2032 tracker_pb2.ComponentDef(component_id=1, path='UI'),
2033 tracker_pb2.ComponentDef(component_id=2, path='DB')]
2034 self.assertEqual(
2035 tracker_bizobj.MakeAmendment(
2036 tracker_pb2.FieldID.COMPONENTS, '', [], []),
2037 tracker_bizobj.MakeComponentsAmendment([], [], config))
2038
2039 def testMakeComponentsAmendment_NotFound(self):
2040 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
2041 config.component_defs = [
2042 tracker_pb2.ComponentDef(component_id=1, path='UI'),
2043 tracker_pb2.ComponentDef(component_id=2, path='DB')]
2044 self.assertEqual(
2045 tracker_bizobj.MakeAmendment(
2046 tracker_pb2.FieldID.COMPONENTS, '', [], []),
2047 tracker_bizobj.MakeComponentsAmendment([99], [999], config))
2048
2049 def testMakeComponentsAmendment_Normal(self):
2050 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
2051 config.component_defs = [
2052 tracker_pb2.ComponentDef(component_id=1, path='UI'),
2053 tracker_pb2.ComponentDef(component_id=2, path='DB')]
2054 self.assertEqual(
2055 tracker_bizobj.MakeAmendment(
2056 tracker_pb2.FieldID.COMPONENTS, '-UI DB', [], []),
2057 tracker_bizobj.MakeComponentsAmendment([2], [1], config))
2058
2059 def testMakeBlockedOnAmendment(self):
2060 ref1 = (None, 1)
2061 ref2 = ('other-proj', 2)
2062 amendment = tracker_bizobj.MakeBlockedOnAmendment([ref1], [ref2])
2063 self.assertEqual(tracker_pb2.FieldID.BLOCKEDON, amendment.field)
2064 self.assertEqual('-other-proj:2 1', amendment.newvalue)
2065
2066 amendment = tracker_bizobj.MakeBlockedOnAmendment([ref2], [ref1])
2067 self.assertEqual(tracker_pb2.FieldID.BLOCKEDON, amendment.field)
2068 self.assertEqual('-1 other-proj:2', amendment.newvalue)
2069
2070 def testMakeBlockingAmendment(self):
2071 ref1 = (None, 1)
2072 ref2 = ('other-proj', 2)
2073 amendment = tracker_bizobj.MakeBlockingAmendment([ref1], [ref2])
2074 self.assertEqual(tracker_pb2.FieldID.BLOCKING, amendment.field)
2075 self.assertEqual('-other-proj:2 1', amendment.newvalue)
2076
2077 def testMakeMergedIntoAmendment(self):
2078 ref1 = (None, 1)
2079 ref2 = ('other-proj', 2)
2080 ref3 = ('chicken-proj', 3)
2081 amendment = tracker_bizobj.MakeMergedIntoAmendment(
2082 [ref1, None], [ref2, ref3])
2083 self.assertEqual(tracker_pb2.FieldID.MERGEDINTO, amendment.field)
2084 self.assertEqual('-other-proj:2 -chicken-proj:3 1', amendment.newvalue)
2085
2086 def testMakeProjectAmendment(self):
2087 self.assertEqual(
2088 tracker_bizobj.MakeAmendment(
2089 tracker_pb2.FieldID.PROJECT, 'moonshot', [], []),
2090 tracker_bizobj.MakeProjectAmendment('moonshot'))
2091
2092 def testAmendmentString(self):
2093 users_by_id = {
2094 111: framework_views.StuffUserView(111, 'username@gmail.com', True),
2095 framework_constants.DELETED_USER_ID: framework_views.StuffUserView(
2096 framework_constants.DELETED_USER_ID, '', True),
2097 }
2098 summary_amendment = tracker_bizobj.MakeSummaryAmendment('new summary', None)
2099 self.assertEqual(
2100 'new summary',
2101 tracker_bizobj.AmendmentString(summary_amendment, users_by_id))
2102
2103 status_amendment = tracker_bizobj.MakeStatusAmendment('', None)
2104 self.assertEqual(
2105 '', tracker_bizobj.AmendmentString(status_amendment, users_by_id))
2106 status_amendment = tracker_bizobj.MakeStatusAmendment('Assigned', 'New')
2107 self.assertEqual(
2108 'Assigned',
2109 tracker_bizobj.AmendmentString(status_amendment, users_by_id))
2110
2111 owner_amendment = tracker_bizobj.MakeOwnerAmendment(0, 0)
2112 self.assertEqual(
2113 '----', tracker_bizobj.AmendmentString(owner_amendment, users_by_id))
2114 owner_amendment = tracker_bizobj.MakeOwnerAmendment(111, 0)
2115 self.assertEqual(
2116 'usern...@gmail.com',
2117 tracker_bizobj.AmendmentString(owner_amendment, users_by_id))
2118
2119 owner_amendment_deleted = tracker_bizobj.MakeOwnerAmendment(1, 0)
2120 self.assertEqual(
2121 framework_constants.DELETED_USER_NAME,
2122 tracker_bizobj.AmendmentString(owner_amendment_deleted, users_by_id))
2123
2124 def testAmendmentString_New(self):
2125 """AmendmentString_New behaves equivalently to the old version."""
2126 # TODO(crbug.com/monorail/7571): Delete this test.
2127 users_by_id = {
2128 111:
2129 framework_views.StuffUserView(111, 'username@gmail.com', True),
2130 framework_constants.DELETED_USER_ID:
2131 framework_views.StuffUserView(
2132 framework_constants.DELETED_USER_ID, '', True),
2133 }
2134 user_display_names = {
2135 111:
2136 'usern...@gmail.com',
2137 framework_constants.DELETED_USER_ID:
2138 framework_constants.DELETED_USER_NAME
2139 }
2140
2141 summary_amendment = tracker_bizobj.MakeSummaryAmendment('new summary', None)
2142 new_str_summary = tracker_bizobj.AmendmentString_New(
2143 summary_amendment, user_display_names)
2144 self.assertEqual(
2145 tracker_bizobj.AmendmentString(summary_amendment, users_by_id),
2146 new_str_summary)
2147
2148 status_amendment = tracker_bizobj.MakeStatusAmendment('', None)
2149 new_str_status = tracker_bizobj.AmendmentString_New(
2150 status_amendment, user_display_names)
2151 self.assertEqual(
2152 tracker_bizobj.AmendmentString(status_amendment, users_by_id),
2153 new_str_status)
2154
2155 status_amendment_2 = tracker_bizobj.MakeStatusAmendment('Assigned', 'New')
2156 new_str_status_2 = tracker_bizobj.AmendmentString_New(
2157 status_amendment_2, user_display_names)
2158 self.assertEqual(
2159 tracker_bizobj.AmendmentString(status_amendment_2, users_by_id),
2160 new_str_status_2)
2161
2162 owner_amendment = tracker_bizobj.MakeOwnerAmendment(0, 0)
2163 new_str_owner = tracker_bizobj.AmendmentString_New(
2164 owner_amendment, user_display_names)
2165 self.assertEqual(
2166 tracker_bizobj.AmendmentString(owner_amendment, users_by_id),
2167 new_str_owner)
2168
2169 owner_amendment_2 = tracker_bizobj.MakeOwnerAmendment(111, 0)
2170 new_str_owner_2 = tracker_bizobj.AmendmentString_New(
2171 owner_amendment_2, user_display_names)
2172 self.assertEqual(
2173 tracker_bizobj.AmendmentString(owner_amendment_2, users_by_id),
2174 new_str_owner_2)
2175
2176 owner_amendment_deleted = tracker_bizobj.MakeOwnerAmendment(1, 0)
2177 new_str_owner_deleted = tracker_bizobj.AmendmentString_New(
2178 owner_amendment_deleted, user_display_names)
2179 self.assertEqual(
2180 tracker_bizobj.AmendmentString(owner_amendment_deleted, users_by_id),
2181 new_str_owner_deleted)
2182
2183
2184 def testAmendmentLinks(self):
2185 users_by_id = {
2186 111: framework_views.StuffUserView(111, 'foo@gmail.com', False),
2187 222: framework_views.StuffUserView(222, 'bar@gmail.com', False),
2188 333: framework_views.StuffUserView(333, 'baz@gmail.com', False),
2189 framework_constants.DELETED_USER_ID: framework_views.StuffUserView(
2190 framework_constants.DELETED_USER_ID, '', True),
2191 }
2192 # SUMMARY
2193 summary_amendment = tracker_bizobj.MakeSummaryAmendment('new summary', None)
2194 self.assertEqual(
2195 [{'value': 'new summary', 'url': None}],
2196 tracker_bizobj.AmendmentLinks(summary_amendment, users_by_id, 'proj'))
2197
2198 summary_amendment = tracker_bizobj.MakeSummaryAmendment(
2199 'new summary', 'NULL')
2200 self.assertEqual(
2201 [{'value': 'new summary', 'url': None}],
2202 tracker_bizobj.AmendmentLinks(summary_amendment, users_by_id, 'proj'))
2203
2204 summary_amendment = tracker_bizobj.MakeSummaryAmendment(
2205 'new summary', 'old info')
2206 self.assertEqual(
2207 [{'value': 'new summary (was: old info)', 'url': None}],
2208 tracker_bizobj.AmendmentLinks(summary_amendment, users_by_id, 'proj'))
2209
2210 # STATUS
2211 status_amendment = tracker_bizobj.MakeStatusAmendment('New', None)
2212 self.assertEqual(
2213 [{'value': 'New', 'url': None}],
2214 tracker_bizobj.AmendmentLinks(status_amendment, users_by_id, 'proj'))
2215
2216 status_amendment = tracker_bizobj.MakeStatusAmendment('New', 'NULL')
2217 self.assertEqual(
2218 [{'value': 'New', 'url': None}],
2219 tracker_bizobj.AmendmentLinks(status_amendment, users_by_id, 'proj'))
2220
2221 status_amendment = tracker_bizobj.MakeStatusAmendment(
2222 'Assigned', 'New')
2223 self.assertEqual(
2224 [{'value': 'Assigned (was: New)', 'url': None}],
2225 tracker_bizobj.AmendmentLinks(status_amendment, users_by_id, 'proj'))
2226
2227 # OWNER
2228 owner_amendment = tracker_bizobj.MakeOwnerAmendment(0, 0)
2229 self.assertEqual(
2230 [{'value': '----', 'url': None}],
2231 tracker_bizobj.AmendmentLinks(owner_amendment, users_by_id, 'proj'))
2232 owner_amendment = tracker_bizobj.MakeOwnerAmendment(111, 0)
2233 self.assertEqual(
2234 [{'value': 'foo@gmail.com', 'url': None}],
2235 tracker_bizobj.AmendmentLinks(owner_amendment, users_by_id, 'proj'))
2236
2237 # BLOCKEDON, BLOCKING, MERGEDINTO
2238 blocking_amendment = tracker_bizobj.MakeBlockingAmendment(
2239 [(None, 123), ('blah', 234)], [(None, 345), ('blah', 456)])
2240 self.assertEqual([
2241 {'value': '-345', 'url': '/p/proj/issues/detail?id=345'},
2242 {'value': '-blah:456', 'url': '/p/blah/issues/detail?id=456'},
2243 {'value': '123', 'url': '/p/proj/issues/detail?id=123'},
2244 {'value': 'blah:234', 'url': '/p/blah/issues/detail?id=234'}],
2245 tracker_bizobj.AmendmentLinks(blocking_amendment, users_by_id, 'proj'))
2246
2247 # newvalue catchall
2248 label_amendment = tracker_bizobj.MakeLabelsAmendment(
2249 ['My-Label', 'Your-Label'], ['Their-Label'])
2250 self.assertEqual([
2251 {'value': '-Their-Label', 'url': None},
2252 {'value': 'My-Label', 'url': None},
2253 {'value': 'Your-Label', 'url': None}],
2254 tracker_bizobj.AmendmentLinks(label_amendment, users_by_id, 'proj'))
2255
2256 # CC, or CUSTOM with user type
2257 cc_amendment = tracker_bizobj.MakeCcAmendment([222, 333], [111])
2258 self.assertEqual([
2259 {'value': '-foo@gmail.com', 'url': None},
2260 {'value': 'bar@gmail.com', 'url': None},
2261 {'value': 'baz@gmail.com', 'url': None}],
2262 tracker_bizobj.AmendmentLinks(cc_amendment, users_by_id, 'proj'))
2263 user_amendment = tracker_bizobj.MakeAmendment(
2264 tracker_pb2.FieldID.CUSTOM, None, [222, 333], [111], 'ultracc')
2265 self.assertEqual([
2266 {'value': '-foo@gmail.com', 'url': None},
2267 {'value': 'bar@gmail.com', 'url': None},
2268 {'value': 'baz@gmail.com', 'url': None}],
2269 tracker_bizobj.AmendmentLinks(user_amendment, users_by_id, 'proj'))
2270
2271 # deleted users
2272 cc_amendment_deleted = tracker_bizobj.MakeCcAmendment(
2273 [framework_constants.DELETED_USER_ID], [])
2274 self.assertEqual(
2275 [{'value': framework_constants.DELETED_USER_NAME, 'url': None}],
2276 tracker_bizobj.AmendmentLinks(
2277 cc_amendment_deleted, users_by_id, 'proj'))
2278
2279 def testGetAmendmentFieldName_Custom(self):
2280 amendment = tracker_bizobj.MakeAmendment(
2281 tracker_pb2.FieldID.CUSTOM, None, [222, 333], [111], 'Rabbit')
2282 self.assertEqual('Rabbit', tracker_bizobj.GetAmendmentFieldName(amendment))
2283
2284 def testGetAmendmentFieldName_Builtin(self):
2285 amendment = tracker_bizobj.MakeAmendment(
2286 tracker_pb2.FieldID.SUMMARY, 'It broke', [], [])
2287 self.assertEqual('Summary', tracker_bizobj.GetAmendmentFieldName(amendment))
2288
2289 def testMakeDanglingIssueRef(self):
2290 di_ref = tracker_bizobj.MakeDanglingIssueRef('proj', 123)
2291 self.assertEqual('proj', di_ref.project)
2292 self.assertEqual(123, di_ref.issue_id)
2293
2294 def testFormatIssueURL_NoRef(self):
2295 self.assertEqual('', tracker_bizobj.FormatIssueURL(None))
2296
2297 def testFormatIssueRef(self):
2298 self.assertEqual('', tracker_bizobj.FormatIssueRef(None))
2299
2300 self.assertEqual(
2301 'p:1', tracker_bizobj.FormatIssueRef(('p', 1)))
2302
2303 self.assertEqual(
2304 '1', tracker_bizobj.FormatIssueRef((None, 1)))
2305
2306 def testFormatIssueRef_External(self):
2307 """Outputs shortlink as-is."""
2308 ref = tracker_pb2.DanglingIssueRef(ext_issue_identifier='b/1234')
2309 self.assertEqual('b/1234', tracker_bizobj.FormatIssueRef(ref))
2310
2311 def testFormatIssueRef_ExternalInvalid(self):
2312 """Does not validate external IDs."""
2313 ref = tracker_pb2.DanglingIssueRef(ext_issue_identifier='invalid')
2314 self.assertEqual('invalid', tracker_bizobj.FormatIssueRef(ref))
2315
2316 def testFormatIssueRef_Empty(self):
2317 """Passes on empty values."""
2318 ref = tracker_pb2.DanglingIssueRef(ext_issue_identifier='')
2319 self.assertEqual('', tracker_bizobj.FormatIssueRef(ref))
2320
2321 def testParseIssueRef(self):
2322 self.assertEqual(None, tracker_bizobj.ParseIssueRef(''))
2323 self.assertEqual(None, tracker_bizobj.ParseIssueRef(' \t '))
2324
2325 ref_pn, ref_id = tracker_bizobj.ParseIssueRef('1')
2326 self.assertEqual(None, ref_pn)
2327 self.assertEqual(1, ref_id)
2328
2329 ref_pn, ref_id = tracker_bizobj.ParseIssueRef('-1')
2330 self.assertEqual(None, ref_pn)
2331 self.assertEqual(1, ref_id)
2332
2333 ref_pn, ref_id = tracker_bizobj.ParseIssueRef('p:2')
2334 self.assertEqual('p', ref_pn)
2335 self.assertEqual(2, ref_id)
2336
2337 ref_pn, ref_id = tracker_bizobj.ParseIssueRef('-p:2')
2338 self.assertEqual('p', ref_pn)
2339 self.assertEqual(2, ref_id)
2340
2341 def testSafeParseIssueRef(self):
2342 self.assertEqual(None, tracker_bizobj._SafeParseIssueRef('-'))
2343 self.assertEqual(None, tracker_bizobj._SafeParseIssueRef('test:'))
2344 ref_pn, ref_id = tracker_bizobj.ParseIssueRef('p:2')
2345 self.assertEqual('p', ref_pn)
2346 self.assertEqual(2, ref_id)
2347
2348 def testMergeFields_NoChange(self):
2349 fv1 = tracker_bizobj.MakeFieldValue(1, 42, None, None, None, None, False)
2350 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2351 [fv1], [], [], [])
2352 self.assertEqual([fv1], merged_fvs)
2353 self.assertEqual({}, fvs_added_dict)
2354 self.assertEqual({}, fvs_removed_dict)
2355
2356 def testMergeFields_SingleValued(self):
2357 fd = tracker_pb2.FieldDef(field_id=1, field_name='foo')
2358 fv1 = tracker_bizobj.MakeFieldValue(1, 42, None, None, None, None, False)
2359 fv2 = tracker_bizobj.MakeFieldValue(1, 43, None, None, None, None, False)
2360 fv3 = tracker_bizobj.MakeFieldValue(1, 44, None, None, None, None, False)
2361
2362 # Adding one replaces all values since the field is single-valued.
2363 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2364 [fv1, fv2], [fv3], [], [fd])
2365 self.assertEqual([fv3], merged_fvs)
2366 self.assertEqual({fv3.field_id: [fv3]}, fvs_added_dict)
2367 self.assertEqual({}, fvs_removed_dict)
2368
2369 # Removing one just removes it, does not reset.
2370 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2371 [fv1, fv2], [], [fv2], [fd])
2372 self.assertEqual([fv1], merged_fvs)
2373 self.assertEqual({}, fvs_added_dict)
2374 self.assertEqual({fv2.field_id: [fv2]}, fvs_removed_dict)
2375
2376 def testMergeFields_SingleValuedPhase(self):
2377 fd = tracker_pb2.FieldDef(
2378 field_id=1, field_name='phase-foo', is_phase_field=True)
2379 fv1 = tracker_bizobj.MakeFieldValue(
2380 1, 45, None, None, None, None, False, phase_id=1)
2381 fv2 = tracker_bizobj.MakeFieldValue(
2382 1, 46, None, None, None, None, False, phase_id=2)
2383 fv3 = tracker_bizobj.MakeFieldValue(
2384 1, 47, None, None, None, None, False, phase_id=1) # should replace fv4
2385
2386 # Adding one replaces all values since the field is single-valued.
2387 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2388 [fv1, fv2], [fv3], [], [fd])
2389 self.assertEqual([fv2, fv3], merged_fvs)
2390 self.assertEqual({fv3.field_id: [fv3]}, fvs_added_dict)
2391 self.assertEqual({}, fvs_removed_dict)
2392
2393 # Removing one just removes it, does not reset.
2394 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2395 [fv1, fv2], [], [fv2], [fd])
2396 self.assertEqual([fv1], merged_fvs)
2397 self.assertEqual({}, fvs_added_dict)
2398 self.assertEqual({fv2.field_id: [fv2]}, fvs_removed_dict)
2399
2400 def testMergeFields_MultiValued(self):
2401 fd = tracker_pb2.FieldDef(
2402 field_id=1, field_name='foo', is_multivalued=True)
2403 fv1 = tracker_bizobj.MakeFieldValue(1, 42, None, None, None, None, False)
2404 fv2 = tracker_bizobj.MakeFieldValue(1, 43, None, None, None, None, False)
2405 fv3 = tracker_bizobj.MakeFieldValue(1, 44, None, None, None, None, False)
2406 fv4 = tracker_bizobj.MakeFieldValue(1, 42, None, None, None, None, False)
2407 fv5 = tracker_bizobj.MakeFieldValue(1, 99, None, None, None, None, False)
2408 fv6 = tracker_bizobj.MakeFieldValue(1, 100, None, None, None, None, False)
2409
2410 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2411 [fv1, fv2], [fv2, fv3, fv6], [fv4, fv5], [fd])
2412 self.assertEqual([fv2, fv3, fv6], merged_fvs)
2413 self.assertEqual({fv3.field_id: [fv3, fv6]}, fvs_added_dict)
2414 self.assertEqual({fv4.field_id: [fv4]}, fvs_removed_dict)
2415
2416 def testMergeFields_MultiValuedPhase(self):
2417 fd = tracker_pb2.FieldDef(
2418 field_id=1, field_name='foo', is_multivalued=True, is_phase_field=True)
2419 fd2 = tracker_pb2.FieldDef(
2420 field_id=2, field_name='cow', is_multivalued=True, is_phase_field=True)
2421 fv1 = tracker_bizobj.MakeFieldValue(
2422 1, 42, None, None, None, None, False, phase_id=1)
2423 fv2 = tracker_bizobj.MakeFieldValue(
2424 1, 43, None, None, None, None, False, phase_id=2)
2425 fv3 = tracker_bizobj.MakeFieldValue(
2426 1, 44, None, None, None, None, False, phase_id=1)
2427 fv4 = tracker_bizobj.MakeFieldValue(
2428 1, 99, None, None, None, None, False, phase_id=2)
2429 fv5 = tracker_bizobj.MakeFieldValue(
2430 2, 22, None, None, None, None, False, phase_id=2)
2431
2432 merged_fvs, fvs_added_dict, fvs_removed_dict = tracker_bizobj._MergeFields(
2433 [fv1, fv2], [fv3, fv1, fv5], [fv2, fv4], [fd, fd2])
2434 self.assertEqual([fv1, fv3, fv5], merged_fvs)
2435 self.assertEqual({fv3.field_id: [fv3], fv5.field_id: [fv5]}, fvs_added_dict)
2436 self.assertEqual({fv2.field_id: [fv2]}, fvs_removed_dict)
2437
2438 def testSplitBlockedOnRanks_Normal(self):
2439 issue = tracker_pb2.Issue()
2440 issue.blocked_on_iids = [78902, 78903, 78904]
2441 issue.blocked_on_ranks = [10, 20, 30]
2442 rank_rows = list(zip(issue.blocked_on_iids, issue.blocked_on_ranks))
2443 rank_rows.reverse()
2444 ret = tracker_bizobj.SplitBlockedOnRanks(
2445 issue, 78903, False, issue.blocked_on_iids)
2446 self.assertEqual(ret, (rank_rows[:1], rank_rows[1:]))
2447
2448 def testSplitBlockedOnRanks_BadTarget(self):
2449 issue = tracker_pb2.Issue()
2450 issue.blocked_on_iids = [78902, 78903, 78904]
2451 issue.blocked_on_ranks = [10, 20, 30]
2452 rank_rows = list(zip(issue.blocked_on_iids, issue.blocked_on_ranks))
2453 rank_rows.reverse()
2454 ret = tracker_bizobj.SplitBlockedOnRanks(
2455 issue, 78999, False, issue.blocked_on_iids)
2456 self.assertEqual(ret, (rank_rows, []))