blob: ac94d57330a01b6cd8a5c4170a201433abc6d568 [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2016 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""Tests for the API v1 helpers."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import datetime
11import mock
12import unittest
13
14from framework import framework_constants
15from framework import permissions
16from framework import profiler
17from services import api_pb2_v1_helpers
18from services import service_manager
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010019from mrproto import api_pb2_v1
20from mrproto import project_pb2
21from mrproto import tracker_pb2
22from mrproto import usergroup_pb2
Copybara854996b2021-09-07 19:36:02 +000023from testing import fake
24from tracker import tracker_bizobj
25
26
27def MakeTemplate(prefix):
28 return tracker_pb2.TemplateDef(
29 name='%s-template' % prefix,
30 content='%s-content' % prefix,
31 summary='%s-summary' % prefix,
32 summary_must_be_edited=True,
33 status='New',
34 labels=['%s-label1' % prefix, '%s-label2' % prefix],
35 members_only=True,
36 owner_defaults_to_member=True,
37 component_required=True,
38 )
39
40
41def MakeLabel(prefix):
42 return tracker_pb2.LabelDef(
43 label='%s-label' % prefix,
44 label_docstring='%s-description' % prefix
45 )
46
47
48def MakeStatus(prefix):
49 return tracker_pb2.StatusDef(
50 status='%s-New' % prefix,
51 means_open=True,
52 status_docstring='%s-status' % prefix
53 )
54
55
56def MakeProjectIssueConfig(prefix):
57 return tracker_pb2.ProjectIssueConfig(
58 restrict_to_known=True,
59 default_col_spec='ID Type Priority Summary',
60 default_sort_spec='ID Priority',
61 well_known_statuses=[
62 MakeStatus('%s-status1' % prefix),
63 MakeStatus('%s-status2' % prefix),
64 ],
65 well_known_labels=[
66 MakeLabel('%s-label1' % prefix),
67 MakeLabel('%s-label2' % prefix),
68 ],
69 default_template_for_developers=1,
70 default_template_for_users=2
71 )
72
73
74def MakeProject(prefix):
75 return project_pb2.MakeProject(
76 project_name='%s-project' % prefix,
77 summary='%s-summary' % prefix,
78 description='%s-description' % prefix,
79 )
80
81
82class ApiV1HelpersTest(unittest.TestCase):
83
84 def setUp(self):
85 self.services = service_manager.Services(
86 user=fake.UserService(),
87 issue=fake.IssueService(),
88 project=fake.ProjectService(),
89 config=fake.ConfigService(),
90 issue_star=fake.IssueStarService())
91 self.services.user.TestAddUser('user@example.com', 111)
92 self.person_1 = api_pb2_v1_helpers.convert_person(111, None, self.services)
93
94 def testConvertTemplate(self):
95 """Test convert_template."""
96 template = MakeTemplate('test')
97 prompt = api_pb2_v1_helpers.convert_template(template)
98 self.assertEqual(template.name, prompt.name)
99 self.assertEqual(template.summary, prompt.title)
100 self.assertEqual(template.content, prompt.description)
101 self.assertEqual(template.summary_must_be_edited, prompt.titleMustBeEdited)
102 self.assertEqual(template.status, prompt.status)
103 self.assertEqual(template.labels, prompt.labels)
104 self.assertEqual(template.members_only, prompt.membersOnly)
105 self.assertEqual(template.owner_defaults_to_member, prompt.defaultToMember)
106 self.assertEqual(template.component_required, prompt.componentRequired)
107
108 def testConvertLabel(self):
109 """Test convert_label."""
110 labeldef = MakeLabel('test')
111 label = api_pb2_v1_helpers.convert_label(labeldef)
112 self.assertEqual(labeldef.label, label.label)
113 self.assertEqual(labeldef.label_docstring, label.description)
114
115 def testConvertStatus(self):
116 """Test convert_status."""
117 statusdef = MakeStatus('test')
118 status = api_pb2_v1_helpers.convert_status(statusdef)
119 self.assertEqual(statusdef.status, status.status)
120 self.assertEqual(statusdef.means_open, status.meansOpen)
121 self.assertEqual(statusdef.status_docstring, status.description)
122
123 def testConvertProjectIssueConfig(self):
124 """Test convert_project_config."""
125 prefix = 'test'
126 config = MakeProjectIssueConfig(prefix)
127 templates = [
128 MakeTemplate('%s-template1' % prefix),
129 MakeTemplate('%s-template2' % prefix),
130 ]
131 config_api = api_pb2_v1_helpers.convert_project_config(config, templates)
132 self.assertEqual(config.restrict_to_known, config_api.restrictToKnown)
133 self.assertEqual(config.default_col_spec.split(), config_api.defaultColumns)
134 self.assertEqual(
135 config.default_sort_spec.split(), config_api.defaultSorting)
136 self.assertEqual(2, len(config_api.statuses))
137 self.assertEqual(2, len(config_api.labels))
138 self.assertEqual(2, len(config_api.prompts))
139 self.assertEqual(
140 config.default_template_for_developers,
141 config_api.defaultPromptForMembers)
142 self.assertEqual(
143 config.default_template_for_users,
144 config_api.defaultPromptForNonMembers)
145
146 def testConvertProject(self):
147 """Test convert_project."""
148 project = MakeProject('testprj')
149 prefix = 'testconfig'
150 config = MakeProjectIssueConfig(prefix)
151 role = api_pb2_v1.Role.owner
152 templates = [
153 MakeTemplate('%s-template1' % prefix),
154 MakeTemplate('%s-template2' % prefix),
155 ]
156 project_api = api_pb2_v1_helpers.convert_project(project, config, role,
157 templates)
158 self.assertEqual(project.project_name, project_api.name)
159 self.assertEqual(project.project_name, project_api.externalId)
160 self.assertEqual('/p/%s/' % project.project_name, project_api.htmlLink)
161 self.assertEqual(project.summary, project_api.summary)
162 self.assertEqual(project.description, project_api.description)
163 self.assertEqual(role, project_api.role)
164 self.assertIsInstance(
165 project_api.issuesConfig, api_pb2_v1.ProjectIssueConfig)
166
167 def testConvertPerson(self):
168 """Test convert_person."""
169 result = api_pb2_v1_helpers.convert_person(111, None, self.services)
170 self.assertIsInstance(result, api_pb2_v1.AtomPerson)
171 self.assertEqual('user@example.com', result.name)
172
173 none_user = api_pb2_v1_helpers.convert_person(None, '', self.services)
174 self.assertIsNone(none_user)
175
176 deleted_user = api_pb2_v1_helpers.convert_person(
177 framework_constants.DELETED_USER_ID, '', self.services)
178 self.assertEqual(
179 deleted_user,
180 api_pb2_v1.AtomPerson(
181 kind='monorail#issuePerson',
182 name=framework_constants.DELETED_USER_NAME))
183
184 def testConvertIssueIDs(self):
185 """Test convert_issue_ids."""
186 issue1 = fake.MakeTestIssue(789, 1, 'one', 'New', 111)
187 self.services.issue.TestAddIssue(issue1)
188 issue_ids = [100001]
189 mar = mock.Mock()
190 mar.cnxn = None
191 mar.project_name = 'test-project'
192 result = api_pb2_v1_helpers.convert_issue_ids(issue_ids, mar, self.services)
193 self.assertEqual(1, len(result))
194 self.assertEqual(1, result[0].issueId)
195
196 def testConvertIssueRef(self):
197 """Test convert_issueref_pbs."""
198 issue1 = fake.MakeTestIssue(12345, 1, 'one', 'New', 111)
199 self.services.issue.TestAddIssue(issue1)
200 self.services.project.TestAddProject(
201 'test-project', owner_ids=[2],
202 project_id=12345)
203 mar = mock.Mock()
204 mar.cnxn = None
205 mar.project_name = 'test-project'
206 mar.project_id = 12345
207 ir = api_pb2_v1.IssueRef(
208 issueId=1,
209 projectId='test-project'
210 )
211 result = api_pb2_v1_helpers.convert_issueref_pbs([ir], mar, self.services)
212 self.assertEqual(1, len(result))
213 self.assertEqual(100001, result[0])
214
215 def testConvertIssue(self):
216 """Convert an internal Issue PB to an IssueWrapper API PB."""
217 self.services.project.TestAddProject(
218 'test-project', owner_ids=[2], project_id=12345)
219 self.services.user.TestAddUser('user@example.com', 111)
220
221 mar = mock.Mock()
222 mar.cnxn = None
223 mar.project_name = 'test-project'
224 mar.project_id = 12345
225 mar.auth.effective_ids = {111}
226 mar.perms = permissions.READ_ONLY_PERMISSIONSET
227 mar.profiler = profiler.Profiler()
228 mar.config = tracker_bizobj.MakeDefaultProjectIssueConfig(12345)
229 mar.config.field_defs = [
230 tracker_bizobj.MakeFieldDef(
231 1, 12345, 'EstDays', tracker_pb2.FieldTypes.INT_TYPE, None, None,
232 False, False, False, None, None, None, False, None, None, None,
233 None, 'doc', False, approval_id=2),
234 tracker_bizobj.MakeFieldDef(
235 2, 12345, 'DesignReview', tracker_pb2.FieldTypes.APPROVAL_TYPE,
236 None, None, False, False, False, None, None, None, False, None,
237 None, None, None, 'doc', False),
238 tracker_bizobj.MakeFieldDef(
239 3, 12345, 'StringField', tracker_pb2.FieldTypes.STR_TYPE, None,
240 None, False, False, False, None, None, None, False, None, None,
241 None, None, 'doc', False),
242 tracker_bizobj.MakeFieldDef(
243 4, 12345, 'DressReview', tracker_pb2.FieldTypes.APPROVAL_TYPE,
244 None, None, False, False, False, None, None, None, False, None,
245 None, None, None, 'doc', False),
246 ]
247 self.services.config.StoreConfig(mar.cnxn, mar.config)
248
249 now = 1472067725
250 now_dt = datetime.datetime.fromtimestamp(now)
251
252 fvs = [
253 tracker_bizobj.MakeFieldValue(
254 1, 4, None, None, None, None, False, phase_id=4),
255 tracker_bizobj.MakeFieldValue(
256 3, None, 'string', None, None, None, False, phase_id=4),
257 # missing phase
258 tracker_bizobj.MakeFieldValue(
259 3, None, u'\xe2\x9d\xa4\xef\xb8\x8f', None, None, None, False,
260 phase_id=2),
261 ]
262 phases = [
263 tracker_pb2.Phase(phase_id=3, name="JustAPhase", rank=4),
264 tracker_pb2.Phase(phase_id=4, name="NotAPhase", rank=9)
265 ]
266 approval_values = [
267 tracker_pb2.ApprovalValue(
268 approval_id=2, phase_id=3, approver_ids=[111]),
269 tracker_pb2.ApprovalValue(approval_id=4, approver_ids=[111])
270 ]
271 issue = fake.MakeTestIssue(
272 12345, 1, 'one', 'New', 111, field_values=fvs,
273 approval_values=approval_values, phases=phases)
274 issue.opened_timestamp = now
275 issue.owner_modified_timestamp = now
276 issue.status_modified_timestamp = now
277 issue.component_modified_timestamp = now
278 # TODO(jrobbins): set up a lot more fields.
279
280 for cls in [api_pb2_v1.IssueWrapper, api_pb2_v1.IssuesGetInsertResponse]:
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100281 result = api_pb2_v1_helpers.convert_issue(
282 cls, issue, mar, self.services, migrated_id='12345')
Copybara854996b2021-09-07 19:36:02 +0000283 self.assertEqual(1, result.id)
284 self.assertEqual('one', result.title)
285 self.assertEqual('one', result.summary)
286 self.assertEqual(now_dt, result.published)
287 self.assertEqual(now_dt, result.owner_modified)
288 self.assertEqual(now_dt, result.status_modified)
289 self.assertEqual(now_dt, result.component_modified)
290 self.assertEqual(
291 result.fieldValues, [
292 api_pb2_v1.FieldValue(
293 fieldName='EstDays',
294 fieldValue='4',
295 approvalName='DesignReview',
296 derived=False),
297 api_pb2_v1.FieldValue(
298 fieldName='StringField',
299 fieldValue='string',
300 phaseName="NotAPhase",
301 derived=False),
302 api_pb2_v1.FieldValue(
303 fieldName='StringField',
304 fieldValue=u'\xe2\x9d\xa4\xef\xb8\x8f',
305 derived=False),
306 ])
307 self.assertEqual(
308 result.approvalValues,
309 [api_pb2_v1.Approval(
310 approvalName="DesignReview",
311 approvers=[self.person_1],
312 status=api_pb2_v1.ApprovalStatus.notSet,
313 phaseName="JustAPhase",
314 ),
315 api_pb2_v1.Approval(
316 approvalName="DressReview",
317 approvers=[self.person_1],
318 status=api_pb2_v1.ApprovalStatus.notSet,
319 )]
320 )
321 self.assertEqual(
322 result.phases,
323 [api_pb2_v1.Phase(phaseName="JustAPhase", rank=4),
324 api_pb2_v1.Phase(phaseName="NotAPhase", rank=9)
325 ])
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100326 self.assertEqual('12345', result.migrated_id)
Copybara854996b2021-09-07 19:36:02 +0000327
328 # TODO(jrobbins): check a lot more fields.
329
330 def testConvertAttachment(self):
331 """Test convert_attachment."""
332
333 attachment = tracker_pb2.Attachment(
334 attachment_id=1,
335 filename='stats.txt',
336 filesize=12345,
337 mimetype='text/plain',
338 deleted=False)
339
340 result = api_pb2_v1_helpers.convert_attachment(attachment)
341 self.assertEqual(attachment.attachment_id, result.attachmentId)
342 self.assertEqual(attachment.filename, result.fileName)
343 self.assertEqual(attachment.filesize, result.fileSize)
344 self.assertEqual(attachment.mimetype, result.mimetype)
345 self.assertEqual(attachment.deleted, result.isDeleted)
346
347 def testConvertAmendments(self):
348 """Test convert_amendments."""
349 self.services.user.TestAddUser('user2@example.com', 222)
350 mar = mock.Mock()
351 mar.cnxn = None
352 issue = mock.Mock()
353 issue.project_name = 'test-project'
354
355 amendment_summary = tracker_pb2.Amendment(
356 field=tracker_pb2.FieldID.SUMMARY,
357 newvalue='new summary')
358 amendment_status = tracker_pb2.Amendment(
359 field=tracker_pb2.FieldID.STATUS,
360 newvalue='new status')
361 amendment_owner = tracker_pb2.Amendment(
362 field=tracker_pb2.FieldID.OWNER,
363 added_user_ids=[111])
364 amendment_labels = tracker_pb2.Amendment(
365 field=tracker_pb2.FieldID.LABELS,
366 newvalue='label1 -label2')
367 amendment_cc_add = tracker_pb2.Amendment(
368 field=tracker_pb2.FieldID.CC,
369 added_user_ids=[111])
370 amendment_cc_remove = tracker_pb2.Amendment(
371 field=tracker_pb2.FieldID.CC,
372 removed_user_ids=[222])
373 amendment_blockedon = tracker_pb2.Amendment(
374 field=tracker_pb2.FieldID.BLOCKEDON,
375 newvalue='1')
376 amendment_blocking = tracker_pb2.Amendment(
377 field=tracker_pb2.FieldID.BLOCKING,
378 newvalue='other:2 -3')
379 amendment_mergedinto = tracker_pb2.Amendment(
380 field=tracker_pb2.FieldID.MERGEDINTO,
381 newvalue='4')
382 amendments = [
383 amendment_summary, amendment_status, amendment_owner,
384 amendment_labels, amendment_cc_add, amendment_cc_remove,
385 amendment_blockedon, amendment_blocking, amendment_mergedinto]
386
387 result = api_pb2_v1_helpers.convert_amendments(
388 issue, amendments, mar, self.services)
389 self.assertEqual(amendment_summary.newvalue, result.summary)
390 self.assertEqual(amendment_status.newvalue, result.status)
391 self.assertEqual('user@example.com', result.owner)
392 self.assertEqual(['label1', '-label2'], result.labels)
393 self.assertEqual(['user@example.com', '-user2@example.com'], result.cc)
394 self.assertEqual(['test-project:1'], result.blockedOn)
395 self.assertEqual(['other:2', '-test-project:3'], result.blocking)
396 self.assertEqual(amendment_mergedinto.newvalue, result.mergedInto)
397
398 def testConvertApprovalAmendments(self):
399 """Test convert_approval_comment."""
400 self.services.user.TestAddUser('user1@example.com', 111)
401 self.services.user.TestAddUser('user2@example.com', 222)
402 self.services.user.TestAddUser('user3@example.com', 333)
403 mar = mock.Mock()
404 mar.cnxn = None
405 amendment_status = tracker_bizobj.MakeApprovalStatusAmendment(
406 tracker_pb2.ApprovalStatus.APPROVED)
407 amendment_approvers = tracker_bizobj.MakeApprovalApproversAmendment(
408 [111, 222], [333])
409 amendments = [amendment_status, amendment_approvers]
410 result = api_pb2_v1_helpers.convert_approval_amendments(
411 amendments, mar, self.services)
412 self.assertEqual(amendment_status.newvalue, result.status)
413 self.assertEqual(
414 ['user1@example.com', 'user2@example.com', '-user3@example.com'],
415 result.approvers)
416
417 def testConvertComment(self):
418 """Test convert_comment."""
419 mar = mock.Mock()
420 mar.cnxn = None
421 mar.perms = permissions.PermissionSet([])
422 issue = fake.MakeTestIssue(project_id=12345, local_id=1, summary='sum',
423 status='New', owner_id=1001)
424
425 comment = tracker_pb2.IssueComment(
426 user_id=111,
427 content='test content',
428 sequence=1,
429 deleted_by=111,
430 timestamp=1437700000,
431 )
432 result = api_pb2_v1_helpers.convert_comment(
433 issue, comment, mar, self.services, None)
434 self.assertEqual('user@example.com', result.author.name)
435 self.assertEqual(comment.content, result.content)
436 self.assertEqual('user@example.com', result.deletedBy.name)
437 self.assertEqual(1, result.id)
438 # Ensure that the published timestamp falls in a timestamp range to account
439 # for the test being run in different timezones.
440 # Using "Fri, 23 Jul 2015 00:00:00" and "Fri, 25 Jul 2015 00:00:00".
441 self.assertTrue(
442 datetime.datetime(2015, 7, 23, 0, 0, 0) <= result.published <=
443 datetime.datetime(2015, 7, 25, 0, 0, 0))
444 self.assertEqual(result.kind, 'monorail#issueComment')
445
446 def testConvertApprovalComment(self):
447 """Test convert_approval_comment."""
448 mar = mock.Mock()
449 mar.cnxn = None
450 mar.perms = permissions.PermissionSet([])
451 issue = fake.MakeTestIssue(project_id=12345, local_id=1, summary='sum',
452 status='New', owner_id=1001)
453 comment = tracker_pb2.IssueComment(
454 user_id=111,
455 content='test content',
456 sequence=1,
457 deleted_by=111,
458 timestamp=1437700000,
459 )
460 result = api_pb2_v1_helpers.convert_approval_comment(
461 issue, comment, mar, self.services, None)
462 self.assertEqual('user@example.com', result.author.name)
463 self.assertEqual(comment.content, result.content)
464 self.assertEqual('user@example.com', result.deletedBy.name)
465 self.assertEqual(1, result.id)
466 # Ensure that the published timestamp falls in a timestamp range to account
467 # for the test being run in different timezones.
468 # Using "Fri, 23 Jul 2015 00:00:00" and "Fri, 25 Jul 2015 00:00:00".
469 self.assertTrue(
470 datetime.datetime(2015, 7, 23, 0, 0, 0) <= result.published <=
471 datetime.datetime(2015, 7, 25, 0, 0, 0))
472 self.assertEqual(result.kind, 'monorail#approvalComment')
473
474
475 def testGetUserEmail(self):
476 email = api_pb2_v1_helpers._get_user_email(self.services.user, '', 111)
477 self.assertEqual('user@example.com', email)
478
479 no_user_found = api_pb2_v1_helpers._get_user_email(
480 self.services.user, '', 222)
481 self.assertEqual(framework_constants.USER_NOT_FOUND_NAME, no_user_found)
482
483 deleted = api_pb2_v1_helpers._get_user_email(
484 self.services.user, '', framework_constants.DELETED_USER_ID)
485 self.assertEqual(framework_constants.DELETED_USER_NAME, deleted)
486
487 none_user_id = api_pb2_v1_helpers._get_user_email(
488 self.services.user, '', None)
489 self.assertEqual(framework_constants.NO_USER_NAME, none_user_id)
490
491 def testSplitRemoveAdd(self):
492 """Test split_remove_add."""
493
494 items = ['1', '-2', '-3', '4']
495 list_to_add, list_to_remove = api_pb2_v1_helpers.split_remove_add(items)
496
497 self.assertEqual(['1', '4'], list_to_add)
498 self.assertEqual(['2', '3'], list_to_remove)
499
500 def testIssueGlobalIDs(self):
501 """Test issue_global_ids."""
502 issue1 = fake.MakeTestIssue(12345, 1, 'one', 'New', 111)
503 self.services.issue.TestAddIssue(issue1)
504 self.services.project.TestAddProject(
505 'test-project', owner_ids=[2],
506 project_id=12345)
507 mar = mock.Mock()
508 mar.cnxn = None
509 mar.project_name = 'test-project'
510 mar.project_id = 12345
511 pairs = ['test-project:1']
512 result = api_pb2_v1_helpers.issue_global_ids(
513 pairs, 12345, mar, self.services)
514 self.assertEqual(100001, result[0])
515
516 def testConvertGroupSettings(self):
517 """Test convert_group_settings."""
518
519 setting = usergroup_pb2.MakeSettings('owners', 'mdb', 0)
520 result = api_pb2_v1_helpers.convert_group_settings('test-group', setting)
521 self.assertEqual('test-group', result.groupName)
522 self.assertEqual(setting.who_can_view_members, result.who_can_view_members)
523 self.assertEqual(setting.ext_group_type, result.ext_group_type)
524 self.assertEqual(setting.last_sync_time, result.last_sync_time)
525
526 def testConvertComponentDef(self):
527 pass # TODO(jrobbins): Fill in this test.
528
529 def testConvertComponentIDs(self):
530 pass # TODO(jrobbins): Fill in this test.
531
532 def testConvertFieldValues_Empty(self):
533 """The client's request might not have any field edits."""
534 mar = mock.Mock()
535 mar.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
536
537 field_values = []
538 actual = api_pb2_v1_helpers.convert_field_values(
539 field_values, mar, self.services)
540 (fv_list_add, fv_list_remove, fv_list_clear,
541 label_list_add, label_list_remove) = actual
542 self.assertEqual([], fv_list_add)
543 self.assertEqual([], fv_list_remove)
544 self.assertEqual([], fv_list_clear)
545 self.assertEqual([], label_list_add)
546 self.assertEqual([], label_list_remove)
547
548 def testConvertFieldValues_Normal(self):
549 """The client wants to edit a custom field."""
550 mar = mock.Mock()
551 mar.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
552 mar.config.field_defs = [
553 tracker_bizobj.MakeFieldDef(
554 1, 789, 'Priority', tracker_pb2.FieldTypes.ENUM_TYPE, None, None,
555 False, False, False, None, None, None, False, None, None, None,
556 None, 'doc', False),
557 tracker_bizobj.MakeFieldDef(
558 2, 789, 'EstDays', tracker_pb2.FieldTypes.INT_TYPE, None, None,
559 False, False, False, 0, 99, None, False, None, None, None,
560 None, 'doc', False),
561 tracker_bizobj.MakeFieldDef(
562 3, 789, 'Nickname', tracker_pb2.FieldTypes.STR_TYPE, None, None,
563 False, False, False, None, None, None, False, None, None, None,
564 None, 'doc', False),
565 tracker_bizobj.MakeFieldDef(
566 4, 789, 'Verifier', tracker_pb2.FieldTypes.USER_TYPE, None, None,
567 False, False, False, None, None, None, False, None, None, None,
568 None, 'doc', False),
569 tracker_bizobj.MakeFieldDef(
570 5, 789, 'Deadline', tracker_pb2.FieldTypes.DATE_TYPE, None, None,
571 False, False, False, None, None, None, False, None, None, None,
572 None, 'doc', False),
573 tracker_bizobj.MakeFieldDef(
574 6, 789, 'Homepage', tracker_pb2.FieldTypes.URL_TYPE, None, None,
575 False, False, False, None, None, None, False, None, None, None,
576 None, 'doc', False),
577 ]
578 field_values = [
579 api_pb2_v1.FieldValue(fieldName='Priority', fieldValue='High'),
580 api_pb2_v1.FieldValue(fieldName='EstDays', fieldValue='4'),
581 api_pb2_v1.FieldValue(fieldName='Nickname', fieldValue='Scout'),
582 api_pb2_v1.FieldValue(
583 fieldName='Verifier', fieldValue='user@example.com'),
584 api_pb2_v1.FieldValue(fieldName='Deadline', fieldValue='2017-12-06'),
585 api_pb2_v1.FieldValue(
586 fieldName='Homepage', fieldValue='http://example.com'),
587 ]
588 actual = api_pb2_v1_helpers.convert_field_values(
589 field_values, mar, self.services)
590 (fv_list_add, fv_list_remove, fv_list_clear,
591 label_list_add, label_list_remove) = actual
592 self.assertEqual(
593 [
594 tracker_bizobj.MakeFieldValue(2, 4, None, None, None, None, False),
595 tracker_bizobj.MakeFieldValue(
596 3, None, 'Scout', None, None, None, False),
597 tracker_bizobj.MakeFieldValue(
598 4, None, None, 111, None, None, False),
599 tracker_bizobj.MakeFieldValue(
600 5, None, None, None, 1512518400, None, False),
601 tracker_bizobj.MakeFieldValue(
602 6, None, None, None, None, 'http://example.com', False),
603 ], fv_list_add)
604 self.assertEqual([], fv_list_remove)
605 self.assertEqual([], fv_list_clear)
606 self.assertEqual(['Priority-High'], label_list_add)
607 self.assertEqual([], label_list_remove)
608
609 def testConvertFieldValues_ClearAndRemove(self):
610 """The client wants to clear and remove some custom fields."""
611 mar = mock.Mock()
612 mar.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
613 mar.config.field_defs = [
614 tracker_bizobj.MakeFieldDef(
615 1, 789, 'Priority', tracker_pb2.FieldTypes.ENUM_TYPE, None, None,
616 False, False, False, None, None, None, False, None, None, None,
617 None, 'doc', False),
618 tracker_bizobj.MakeFieldDef(
619 11, 789, 'OS', tracker_pb2.FieldTypes.ENUM_TYPE, None, None,
620 False, False, False, None, None, None, False, None, None, None,
621 None, 'doc', False),
622 tracker_bizobj.MakeFieldDef(
623 2, 789, 'EstDays', tracker_pb2.FieldTypes.INT_TYPE, None, None,
624 False, False, False, 0, 99, None, False, None, None, None,
625 None, 'doc', False),
626 tracker_bizobj.MakeFieldDef(
627 3, 789, 'Nickname', tracker_pb2.FieldTypes.STR_TYPE, None, None,
628 False, False, False, None, None, None, False, None, None, None,
629 None, 'doc', False),
630 ]
631 field_values = [
632 api_pb2_v1.FieldValue(
633 fieldName='Priority', fieldValue='High',
634 operator=api_pb2_v1.FieldValueOperator.remove),
635 api_pb2_v1.FieldValue(
636 fieldName='OS', operator=api_pb2_v1.FieldValueOperator.clear),
637 api_pb2_v1.FieldValue(
638 fieldName='EstDays', operator=api_pb2_v1.FieldValueOperator.clear),
639 api_pb2_v1.FieldValue(
640 fieldName='Nickname', fieldValue='Scout',
641 operator=api_pb2_v1.FieldValueOperator.remove),
642 ]
643 actual = api_pb2_v1_helpers.convert_field_values(
644 field_values, mar, self.services)
645 (fv_list_add, fv_list_remove, fv_list_clear,
646 label_list_add, label_list_remove) = actual
647 self.assertEqual([], fv_list_add)
648 self.assertEqual(
649 [
650 tracker_bizobj.MakeFieldValue(
651 3, None, 'Scout', None, None, None, False)
652 ], fv_list_remove)
653 self.assertEqual([11, 2], fv_list_clear)
654 self.assertEqual([], label_list_add)
655 self.assertEqual(['Priority-High'], label_list_remove)
656
657 def testConvertFieldValues_Errors(self):
658 """We don't crash on bad requests."""
659 mar = mock.Mock()
660 mar.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
661 mar.config.field_defs = [
662 tracker_bizobj.MakeFieldDef(
663 2, 789, 'EstDays', tracker_pb2.FieldTypes.INT_TYPE, None, None,
664 False, False, False, 0, 99, None, False, None, None, None,
665 None, 'doc', False),
666 ]
667 field_values = [
668 api_pb2_v1.FieldValue(
669 fieldName='Unknown', operator=api_pb2_v1.FieldValueOperator.clear),
670 ]
671 actual = api_pb2_v1_helpers.convert_field_values(
672 field_values, mar, self.services)
673 (fv_list_add, fv_list_remove, fv_list_clear,
674 label_list_add, label_list_remove) = actual
675 self.assertEqual([], fv_list_add)
676 self.assertEqual([], fv_list_remove)
677 self.assertEqual([], fv_list_clear)
678 self.assertEqual([], label_list_add)
679 self.assertEqual([], label_list_remove)
680
681 def testConvertApprovals(self):
682 """Test we can convert ApprovalValues."""
683 cnxn = None
684 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
685 config.field_defs = [
686 tracker_bizobj.MakeFieldDef(
687 1, 789, 'DesignReview', tracker_pb2.FieldTypes.APPROVAL_TYPE, None,
688 None, False, False, False, None, None, None, False, None, None,
689 None, None, 'doc', False),
690 tracker_bizobj.MakeFieldDef(
691 2, 789, 'PrivacyReview', tracker_pb2.FieldTypes.APPROVAL_TYPE, None,
692 None, False, False, False, 0, 99, None, False, None, None, None,
693 None, 'doc', False),
694 tracker_bizobj.MakeFieldDef(
695 5, 789, 'UXReview', tracker_pb2.FieldTypes.APPROVAL_TYPE, None,
696 None, False, False, False, None, None, None, False, None, None,
697 None, None, 'doc', False),
698 tracker_bizobj.MakeFieldDef(
699 6, 789, 'Homepage', tracker_pb2.FieldTypes.URL_TYPE, None, None,
700 False, False, False, None, None, None, False, None, None, None,
701 None, 'doc', False),
702 ]
703 phases = [
704 tracker_pb2.Phase(phase_id=1),
705 tracker_pb2.Phase(phase_id=2, name="JustAPhase", rank=3),
706 ]
707 ts = 1536260059
708 expected = [
709 api_pb2_v1.Approval(
710 approvalName="DesignReview",
711 approvers=[self.person_1],
712 setter=self.person_1,
713 status=api_pb2_v1.ApprovalStatus.needsReview,
714 setOn=datetime.datetime.fromtimestamp(ts),
715 ),
716 api_pb2_v1.Approval(
717 approvalName="UXReview",
718 approvers=[self.person_1],
719 status=api_pb2_v1.ApprovalStatus.notSet,
720 phaseName="JustAPhase",
721 ),
722 ]
723 avs = [
724 tracker_pb2.ApprovalValue(
725 approval_id=1, approver_ids=[111], setter_id=111,
726 status=tracker_pb2.ApprovalStatus.NEEDS_REVIEW, set_on=ts),
727 tracker_pb2.ApprovalValue(
728 approval_id=5, approver_ids=[111], phase_id=2)
729 ]
730 actual = api_pb2_v1_helpers.convert_approvals(
731 cnxn, avs, self.services, config, phases)
732
733 self.assertEqual(actual, expected)
734
735 def testConvertApprovals_errors(self):
736 """we dont crash on bad requests."""
737 cnxn = None
738 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
739 config.field_defs = [
740 tracker_bizobj.MakeFieldDef(
741 1, 789, 'DesignReview', tracker_pb2.FieldTypes.APPROVAL_TYPE, None,
742 None, False, False, False, None, None, None, False, None, None,
743 None, None, 'doc', False),
744 tracker_bizobj.MakeFieldDef(
745 5, 789, 'UXReview', tracker_pb2.FieldTypes.APPROVAL_TYPE, None,
746 None, False, False, False, None, None, None, False, None, None,
747 None, None, 'doc', False),
748 tracker_bizobj.MakeFieldDef(
749 3, 789, 'DesignDoc', tracker_pb2.FieldTypes.URL_TYPE, None, None,
750 False, False, False, 0, 99, None, False, None, None, None,
751 None, 'doc', False),
752 ]
753 phases = []
754 avs = [
755 tracker_pb2.ApprovalValue(approval_id=1, approver_ids=[111]),
756 # phase does not exist
757 tracker_pb2.ApprovalValue(approval_id=2, phase_id=2),
758 tracker_pb2.ApprovalValue(approval_id=3), # field 3 is not an approval
759 tracker_pb2.ApprovalValue(approval_id=4), # field 4 does not exist
760 ]
761 expected = [
762 api_pb2_v1.Approval(
763 approvalName="DesignReview",
764 approvers=[self.person_1],
765 status=api_pb2_v1.ApprovalStatus.notSet)
766 ]
767
768 actual = api_pb2_v1_helpers.convert_approvals(
769 cnxn, avs, self.services, config, phases)
770 self.assertEqual(actual, expected)
771
772 def testConvertPhases(self):
773 """We can convert Phases."""
774 phases = [
775 tracker_pb2.Phase(name="JustAPhase", rank=1),
776 tracker_pb2.Phase(name="Can'tPhaseMe", rank=4),
777 tracker_pb2.Phase(phase_id=11, rank=5),
778 tracker_pb2.Phase(rank=3),
779 tracker_pb2.Phase(name="Phase"),
780 ]
781 expected = [
782 api_pb2_v1.Phase(phaseName="JustAPhase", rank=1),
783 api_pb2_v1.Phase(phaseName="Can'tPhaseMe", rank=4),
784 api_pb2_v1.Phase(phaseName="Phase"),
785 ]
786 actual = api_pb2_v1_helpers.convert_phases(phases)
787 self.assertEqual(actual, expected)