blob: 5e9f488eaec08763a6398dbd35ecade988ce01fd [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2018 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"""Unit tests for services.template_svc module."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import mock
11import unittest
12
13from mock import Mock, patch
14
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010015from mrproto import tracker_pb2
Copybara854996b2021-09-07 19:36:02 +000016from services import template_svc
17from testing import fake
18from testing import testing_helpers
19from tracker import tracker_bizobj
20from tracker import tracker_constants
21
22
23class TemplateSetTwoLevelCacheTest(unittest.TestCase):
24
25 def setUp(self):
26 self.ts2lc = template_svc.TemplateSetTwoLevelCache(
27 cache_manager=fake.CacheManager(),
28 template_service=Mock(spec=template_svc.TemplateService))
29 self.ts2lc.template_service.template_tbl = Mock()
30
31 def testFetchItems_Empty(self):
32 self.ts2lc.template_service.template_tbl.Select .return_value = []
33 actual = self.ts2lc.FetchItems(cnxn=None, keys=[1, 2])
34 self.assertEqual({1: [], 2: []}, actual)
35
36 def testFetchItems_Normal(self):
37 # pylint: disable=unused-argument
38 def mockSelect(cnxn, cols, project_id, order_by):
39 assert project_id in (1, 2)
40 if project_id == 1:
41 return [
42 (8, 1, 'template-8', 'content', 'summary', False, 111, 'status',
43 False, False, False),
44 (9, 1, 'template-9', 'content', 'summary', False, 111, 'status',
45 True, False, False)]
46 else:
47 return [
48 (7, 2, 'template-7', 'content', 'summary', False, 111, 'status',
49 False, False, False)]
50
51 self.ts2lc.template_service.template_tbl.Select.side_effect = mockSelect
52 actual = self.ts2lc.FetchItems(cnxn=None, keys=[1, 2])
53 expected = {
54 1: [(8, 'template-8', False), (9, 'template-9', True)],
55 2: [(7, 'template-7', False)],
56 }
57 self.assertEqual(expected, actual)
58
59
60class TemplateDefTwoLevelCacheTest(unittest.TestCase):
61
62 def setUp(self):
63 self.template_def_2lc = template_svc.TemplateDefTwoLevelCache(
64 cache_manager=fake.CacheManager(),
65 template_service=Mock(spec=template_svc.TemplateService))
66 self.template_def_2lc.template_service.template_tbl = Mock()
67 self.template_def_2lc.template_service.template2label_tbl = Mock()
68 self.template_def_2lc.template_service.template2component_tbl = Mock()
69 self.template_def_2lc.template_service.template2admin_tbl = Mock()
70 self.template_def_2lc.template_service.template2fieldvalue_tbl = Mock()
71 self.template_def_2lc.template_service.issuephasedef_tbl = Mock()
72 self.template_def_2lc.template_service.template2approvalvalue_tbl = Mock()
73
74 def testFetchItems_Empty(self):
75 self.template_def_2lc.template_service.template_tbl.Select\
76 .return_value = []
77 self.template_def_2lc.template_service.template2label_tbl.Select\
78 .return_value = []
79 self.template_def_2lc.template_service.template2component_tbl.Select\
80 .return_value = []
81 self.template_def_2lc.template_service.template2admin_tbl.Select\
82 .return_value = []
83 self.template_def_2lc.template_service.template2fieldvalue_tbl.Select\
84 .return_value = []
85 self.template_def_2lc.template_service.template2approvalvalue_tbl.Select\
86 .return_value = []
87
88 actual = self.template_def_2lc.FetchItems(cnxn=None, keys=[1, 2])
89 self.assertEqual({}, actual)
90
91 def testFetchItems_Normal(self):
92 template_9_row = (9, 1, 'template-9', 'content', 'summary',
93 False, 111, 'status',
94 False, False, False)
95 template_8_row = (8, 1, 'template-8', 'content', 'summary',
96 False, 111, 'status',
97 False, False, False)
98 template_7_row = (7, 2, 'template-7', 'content', 'summary',
99 False, 111, 'status',
100 False, False, False)
101
102 self.template_def_2lc.template_service.template_tbl.Select\
103 .return_value = [template_7_row, template_8_row,
104 template_9_row]
105 self.template_def_2lc.template_service.template2label_tbl.Select\
106 .return_value = [(9, 'label-1'), (7, 'label-2')]
107 self.template_def_2lc.template_service.template2component_tbl.Select\
108 .return_value = [(9, 13), (7, 14)]
109 self.template_def_2lc.template_service.template2admin_tbl.Select\
110 .return_value = [(9, 111), (7, 222)]
111
112 fv1_row = (15, None, 'fv-1', None, None, None, False)
113 fv2_row = (16, None, 'fv-2', None, None, None, False)
114 fv1 = tracker_bizobj.MakeFieldValue(*fv1_row)
115 fv2 = tracker_bizobj.MakeFieldValue(*fv2_row)
116 self.template_def_2lc.template_service.template2fieldvalue_tbl.Select\
117 .return_value = [((9,) + fv1_row[:-1]), ((7,) + fv2_row[:-1])]
118
119 av1_row = (17, 9, 19, 'na')
120 av2_row = (18, 7, 20, 'not_set')
121 av1 = tracker_pb2.ApprovalValue(approval_id=17, phase_id=19,
122 status=tracker_pb2.ApprovalStatus('NA'))
123 av2 = tracker_pb2.ApprovalValue(approval_id=18, phase_id=20,
124 status=tracker_pb2.ApprovalStatus(
125 'NOT_SET'))
126 phase1_row = (19, 'phase-1', 1)
127 phase2_row = (20, 'phase-2', 2)
128 phase1 = tracker_pb2.Phase(phase_id=19, name='phase-1', rank=1)
129 phase2 = tracker_pb2.Phase(phase_id=20, name='phase-2', rank=2)
130
131 self.template_def_2lc.template_service.template2approvalvalue_tbl.Select\
132 .return_value = [av1_row, av2_row]
133 self.template_def_2lc.template_service.issuephasedef_tbl.Select\
134 .return_value = [phase1_row, phase2_row]
135
136 actual = self.template_def_2lc.FetchItems(cnxn=None, keys=[7, 8, 9])
137 self.assertEqual(3, len(list(actual.keys())))
138 self.assertTrue(isinstance(actual[7], tracker_pb2.TemplateDef))
139 self.assertTrue(isinstance(actual[8], tracker_pb2.TemplateDef))
140 self.assertTrue(isinstance(actual[9], tracker_pb2.TemplateDef))
141
142 self.assertEqual(7, actual[7].template_id)
143 self.assertEqual(8, actual[8].template_id)
144 self.assertEqual(9, actual[9].template_id)
145
146 self.assertEqual(['label-2'], actual[7].labels)
147 self.assertEqual([], actual[8].labels)
148 self.assertEqual(['label-1'], actual[9].labels)
149
150 self.assertEqual([14], actual[7].component_ids)
151 self.assertEqual([], actual[8].component_ids)
152 self.assertEqual([13], actual[9].component_ids)
153
154 self.assertEqual([222], actual[7].admin_ids)
155 self.assertEqual([], actual[8].admin_ids)
156 self.assertEqual([111], actual[9].admin_ids)
157
158 self.assertEqual([fv2], actual[7].field_values)
159 self.assertEqual([], actual[8].field_values)
160 self.assertEqual([fv1], actual[9].field_values)
161
162 self.assertEqual([phase2], actual[7].phases)
163 self.assertEqual([], actual[8].phases)
164 self.assertEqual([phase1], actual[9].phases)
165
166 self.assertEqual([av2], actual[7].approval_values)
167 self.assertEqual([], actual[8].approval_values)
168 self.assertEqual([av1], actual[9].approval_values)
169
170
171class TemplateServiceTest(unittest.TestCase):
172
173 def setUp(self):
174 self.cnxn = Mock()
175 self.template_service = template_svc.TemplateService(fake.CacheManager())
176 self.template_service.template_set_2lc = Mock()
177 self.template_service.template_def_2lc = Mock()
178
179 def testCreateDefaultProjectTemplates_Normal(self):
180 self.template_service.CreateIssueTemplateDef = Mock()
181 self.template_service.CreateDefaultProjectTemplates(self.cnxn, 789)
182
183 expected_calls = [
184 mock.call(self.cnxn, 789, tpl['name'], tpl['content'], tpl['summary'],
185 tpl['summary_must_be_edited'], tpl['status'],
186 tpl.get('members_only', False), True, False, None, tpl['labels'],
187 [], [], [], [])
188 for tpl in tracker_constants.DEFAULT_TEMPLATES]
189 self.template_service.CreateIssueTemplateDef.assert_has_calls(
190 expected_calls, any_order=True)
191
192 def testGetTemplateByName_Normal(self):
193 """GetTemplateByName returns a template that exists."""
194 result_dict = {789: [(1, 'one', 0)]}
195 template = tracker_pb2.TemplateDef(name='one')
196 self.template_service.template_set_2lc.GetAll.return_value = (
197 result_dict, None)
198 self.template_service.template_def_2lc.GetAll.return_value = (
199 {1: template}, None)
200 actual = self.template_service.GetTemplateByName(self.cnxn, 'one', 789)
201 self.assertEqual(actual.template_id, template.template_id)
202
203 def testGetTemplateByName_NotFound(self):
204 """When GetTemplateByName is given the name of a template that does not
205 exist."""
206 result_dict = {789: [(1, 'one', 0)]}
207 template = tracker_pb2.TemplateDef(name='one')
208 self.template_service.template_set_2lc.GetAll.return_value = (
209 result_dict, None)
210 self.template_service.template_def_2lc.GetAll.return_value = (
211 {1: template}, None)
212 actual = self.template_service.GetTemplateByName(self.cnxn, 'two', 789)
213 self.assertEqual(actual, None)
214
215 def testGetTemplateById_Normal(self):
216 """GetTemplateById_Normal returns a template that exists."""
217 template = tracker_pb2.TemplateDef(template_id=1, name='one')
218 self.template_service.template_def_2lc.GetAll.return_value = (
219 {1: template}, None)
220 actual = self.template_service.GetTemplateById(self.cnxn, 1)
221 self.assertEqual(actual.template_id, template.template_id)
222
223 def testGetTemplateById_NotFound(self):
224 """When GetTemplateById is given the ID of a template that does not
225 exist."""
226 self.template_service.template_def_2lc.GetAll.return_value = (
227 {}, None)
228 actual = self.template_service.GetTemplateById(self.cnxn, 1)
229 self.assertEqual(actual, None)
230
231 def testGetTemplatesById_Normal(self):
232 """GetTemplatesById_Normal returns a template that exists."""
233 template = tracker_pb2.TemplateDef(template_id=1, name='one')
234 self.template_service.template_def_2lc.GetAll.return_value = (
235 {1: template}, None)
236 actual = self.template_service.GetTemplatesById(self.cnxn, 1)
237 self.assertEqual(actual[0].template_id, template.template_id)
238
239 def testGetTemplatesById_NotFound(self):
240 """When GetTemplatesById is given the ID of a template that does not
241 exist."""
242 self.template_service.template_def_2lc.GetAll.return_value = (
243 {}, None)
244 actual = self.template_service.GetTemplatesById(self.cnxn, 1)
245 self.assertEqual(actual, [])
246
247 def testGetProjectTemplates_Normal(self):
248 template_set = [(1, 'one', 0), (2, 'two', 1)]
249 result_dict = {789: template_set}
250 self.template_service.template_set_2lc.GetAll.return_value = (
251 result_dict, None)
252 self.template_service.template_def_2lc.GetAll.return_value = (
253 {1: tracker_pb2.TemplateDef()}, None)
254
255 self.assertEqual([tracker_pb2.TemplateDef()],
256 self.template_service.GetProjectTemplates(self.cnxn, 789))
257 self.template_service.template_set_2lc.GetAll.assert_called_once_with(
258 self.cnxn, [789])
259
260 def testExpungeProjectTemplates(self):
261 template_id_rows = [(1,), (2,)]
262 self.template_service.template_tbl.Select = Mock(
263 return_value=template_id_rows)
264 self.template_service.template2label_tbl.Delete = Mock()
265 self.template_service.template2component_tbl.Delete = Mock()
266 self.template_service.template_tbl.Delete = Mock()
267
268 self.template_service.ExpungeProjectTemplates(self.cnxn, 789)
269
270 self.template_service.template_tbl.Select\
271 .assert_called_once_with(self.cnxn, project_id=789, cols=['id'])
272 self.template_service.template2label_tbl.Delete\
273 .assert_called_once_with(self.cnxn, template_id=[1, 2])
274 self.template_service.template2component_tbl.Delete\
275 .assert_called_once_with(self.cnxn, template_id=[1, 2])
276 self.template_service.template_tbl.Delete\
277 .assert_called_once_with(self.cnxn, project_id=789)
278
279
280class CreateIssueTemplateDefTest(TemplateServiceTest):
281
282 def setUp(self):
283 super(CreateIssueTemplateDefTest, self).setUp()
284
285 self.template_service.template_tbl.InsertRow = Mock(return_value=1)
286 self.template_service.template2label_tbl.InsertRows = Mock()
287 self.template_service.template2component_tbl.InsertRows = Mock()
288 self.template_service.template2admin_tbl.InsertRows = Mock()
289 self.template_service.template2fieldvalue_tbl.InsertRows = Mock()
290 self.template_service.issuephasedef_tbl.InsertRow = Mock(return_value=81)
291 self.template_service.template2approvalvalue_tbl.InsertRows = Mock()
292 self.template_service.template_set_2lc._StrToKey = Mock(return_value=789)
293
294 def testCreateIssueTemplateDef(self):
295 fv = tracker_bizobj.MakeFieldValue(
296 1, None, 'somestring', None, None, None, False)
297 av_23 = tracker_pb2.ApprovalValue(
298 approval_id=23, phase_id=11,
299 status=tracker_pb2.ApprovalStatus.NEEDS_REVIEW)
300 av_24 = tracker_pb2.ApprovalValue(approval_id=24, phase_id=11)
301 approval_values = [av_23, av_24]
302 phases = [tracker_pb2.Phase(
303 name='Canary', rank=11, phase_id=11)]
304
305 actual_template_id = self.template_service.CreateIssueTemplateDef(
306 self.cnxn, 789, 'template', 'content', 'summary', True, 'Available',
307 True, True, True, owner_id=111, labels=['label'], component_ids=[3],
308 admin_ids=[222], field_values=[fv], phases=phases,
309 approval_values=approval_values)
310
311 self.assertEqual(1, actual_template_id)
312
313 self.template_service.template_tbl.InsertRow\
314 .assert_called_once_with(self.cnxn, project_id=789, name='template',
315 content='content', summary='summary', summary_must_be_edited=True,
316 owner_id=111, status='Available', members_only=True,
317 owner_defaults_to_member=True, component_required=True,
318 commit=False)
319 self.template_service.template2label_tbl.InsertRows\
320 .assert_called_once_with(self.cnxn, template_svc.TEMPLATE2LABEL_COLS,
321 [(1, 'label')], commit=False)
322 self.template_service.template2component_tbl.InsertRows\
323 .assert_called_once_with(self.cnxn,
324 template_svc.TEMPLATE2COMPONENT_COLS,
325 [(1, 3)], commit=False)
326 self.template_service.template2admin_tbl.InsertRows\
327 .assert_called_once_with(self.cnxn, template_svc.TEMPLATE2ADMIN_COLS,
328 [(1, 222)], commit=False)
329 self.template_service.template2fieldvalue_tbl.InsertRows\
330 .assert_called_once_with(self.cnxn,
331 template_svc.TEMPLATE2FIELDVALUE_COLS,
332 [(1, 1, None, 'somestring', None, None, None)], commit=False)
333 self.template_service.issuephasedef_tbl.InsertRow\
334 .assert_called_once_with(self.cnxn, name='Canary',
335 rank=11, commit=False)
336 self.template_service.template2approvalvalue_tbl.InsertRows\
337 .assert_called_once_with(self.cnxn,
338 template_svc.TEMPLATE2APPROVALVALUE_COLS,
339 [(23, 1, 81, 'needs_review'), (24, 1, 81, 'not_set')], commit=False)
340 self.cnxn.Commit.assert_called_once_with()
341 self.template_service.template_set_2lc.InvalidateKeys\
342 .assert_called_once_with(self.cnxn, [789])
343
344
345class UpdateIssueTemplateDefTest(TemplateServiceTest):
346
347 def setUp(self):
348 super(UpdateIssueTemplateDefTest, self).setUp()
349
350 self.template_service.template_tbl.Update = Mock()
351 self.template_service.template2label_tbl.Delete = Mock()
352 self.template_service.template2label_tbl.InsertRows = Mock()
353 self.template_service.template2admin_tbl.Delete = Mock()
354 self.template_service.template2admin_tbl.InsertRows = Mock()
355 self.template_service.template2approvalvalue_tbl.Delete = Mock()
356 self.template_service.issuephasedef_tbl.InsertRow = Mock(return_value=1)
357 self.template_service.template2approvalvalue_tbl.InsertRows = Mock()
358 self.template_service.template_set_2lc._StrToKey = Mock(return_value=789)
359
360 def testUpdateIssueTemplateDef(self):
361 av_20 = tracker_pb2.ApprovalValue(approval_id=20, phase_id=11)
362 av_21 = tracker_pb2.ApprovalValue(approval_id=21, phase_id=11)
363 approval_values = [av_20, av_21]
364 phases = [tracker_pb2.Phase(
365 name='Canary', phase_id=11, rank=11)]
366 self.template_service.UpdateIssueTemplateDef(
367 self.cnxn, 789, 1, content='content', summary='summary',
368 component_required=True, labels=[], admin_ids=[111],
369 phases=phases, approval_values=approval_values)
370
371 new_values = dict(
372 content='content', summary='summary', component_required=True)
373 self.template_service.template_tbl.Update\
374 .assert_called_once_with(self.cnxn, new_values, id=1, commit=False)
375 self.template_service.template2label_tbl.Delete\
376 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
377 self.template_service.template2label_tbl.InsertRows\
378 .assert_called_once_with(self.cnxn, template_svc.TEMPLATE2LABEL_COLS,
379 [], commit=False)
380 self.template_service.template2admin_tbl.Delete\
381 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
382 self.template_service.template2admin_tbl.InsertRows\
383 .assert_called_once_with(self.cnxn, template_svc.TEMPLATE2ADMIN_COLS,
384 [(1, 111)], commit=False)
385 self.template_service.template2approvalvalue_tbl.Delete\
386 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
387 self.template_service.issuephasedef_tbl.InsertRow\
388 .assert_called_once_with(self.cnxn, name='Canary',
389 rank=11, commit=False)
390 self.template_service.template2approvalvalue_tbl.InsertRows\
391 .assert_called_once_with(self.cnxn,
392 template_svc.TEMPLATE2APPROVALVALUE_COLS,
393 [(20, 1, 1, 'not_set'), (21, 1, 1, 'not_set')], commit=False)
394 self.cnxn.Commit.assert_called_once_with()
395 self.template_service.template_set_2lc.InvalidateKeys\
396 .assert_called_once_with(self.cnxn, [789])
397 self.template_service.template_def_2lc.InvalidateKeys\
398 .assert_called_once_with(self.cnxn, [1])
399
400
401class DeleteTemplateTest(TemplateServiceTest):
402
403 def testDeleteIssueTemplateDef(self):
404 self.template_service.template2label_tbl.Delete = Mock()
405 self.template_service.template2component_tbl.Delete = Mock()
406 self.template_service.template2admin_tbl.Delete = Mock()
407 self.template_service.template2fieldvalue_tbl.Delete = Mock()
408 self.template_service.template2approvalvalue_tbl.Delete = Mock()
409 self.template_service.template_tbl.Delete = Mock()
410 self.template_service.template_set_2lc._StrToKey = Mock(return_value=789)
411
412 self.template_service.DeleteIssueTemplateDef(self.cnxn, 789, 1)
413
414 self.template_service.template2label_tbl.Delete\
415 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
416 self.template_service.template2component_tbl.Delete\
417 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
418 self.template_service.template2admin_tbl.Delete\
419 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
420 self.template_service.template2fieldvalue_tbl.Delete\
421 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
422 self.template_service.template2approvalvalue_tbl.Delete\
423 .assert_called_once_with(self.cnxn, template_id=1, commit=False)
424 self.template_service.template_tbl.Delete\
425 .assert_called_once_with(self.cnxn, id=1, commit=False)
426 self.cnxn.Commit.assert_called_once_with()
427 self.template_service.template_set_2lc.InvalidateKeys\
428 .assert_called_once_with(self.cnxn, [789])
429 self.template_service.template_def_2lc.InvalidateKeys\
430 .assert_called_once_with(self.cnxn, [1])
431
432
433class ExpungeUsersInTemplatesTest(TemplateServiceTest):
434
435 def setUp(self):
436 super(ExpungeUsersInTemplatesTest, self).setUp()
437
438 self.template_service.template2admin_tbl.Delete = Mock()
439 self.template_service.template2fieldvalue_tbl.Delete = Mock()
440 self.template_service.template_tbl.Update = Mock()
441
442 def testExpungeUsersInTemplates(self):
443 user_ids = [111, 222]
444 self.template_service.ExpungeUsersInTemplates(self.cnxn, user_ids, limit=60)
445
446 self.template_service.template2admin_tbl.Delete.assert_called_once_with(
447 self.cnxn, admin_id=user_ids, commit=False, limit=60)
448 self.template_service.template2fieldvalue_tbl\
449 .Delete.assert_called_once_with(
450 self.cnxn, user_id=user_ids, commit=False, limit=60)
451 self.template_service.template_tbl.Update.assert_called_once_with(
452 self.cnxn, {'owner_id': None}, owner_id=user_ids, commit=False)
453
454
455class UnpackTemplateTest(unittest.TestCase):
456
457 def testEmpty(self):
458 with self.assertRaises(ValueError):
459 template_svc.UnpackTemplate(())
460
461 def testNormal(self):
462 row = (1, 2, 'name', 'content', 'summary', False, 3, 'status', False,
463 False, False)
464 self.assertEqual(
465 tracker_pb2.TemplateDef(template_id=1, name='name',
466 content='content', summary='summary', summary_must_be_edited=False,
467 owner_id=3, status='status', members_only=False,
468 owner_defaults_to_member=False,
469 component_required=False),
470 template_svc.UnpackTemplate(row))