blob: 78664c02604a3a47dc4b96220c00dda2707e5f0e [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2018 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"""Unit test for Template creation servlet."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +020011try:
12 from mox3 import mox
13except ImportError:
14 import mox
Copybara854996b2021-09-07 19:36:02 +000015import unittest
16import settings
17
18from mock import Mock
19
20import ezt
21
22from framework import permissions
23from services import service_manager
24from services import template_svc
25from testing import fake
26from testing import testing_helpers
27from tracker import templatecreate
28from tracker import tracker_bizobj
29from tracker import tracker_views
30from proto import tracker_pb2
31
32
33class TemplateCreateTest(unittest.TestCase):
34 """Tests for the TemplateCreate servlet."""
35
36 def setUp(self):
37 self.cnxn = 'fake cnxn'
38 self.services = service_manager.Services(
39 project=fake.ProjectService(),
40 config=fake.ConfigService(),
41 template=Mock(spec=template_svc.TemplateService),
42 user=fake.UserService())
43 self.servlet = templatecreate.TemplateCreate('req', 'res',
44 services=self.services)
45 self.project = self.services.project.TestAddProject('proj')
46
47 self.fd_1 = tracker_bizobj.MakeFieldDef(
48 1, self.project.project_id, 'StringFieldName',
49 tracker_pb2.FieldTypes.STR_TYPE, None, '', False,
50 False, False, None, None, '', False, '', '',
51 tracker_pb2.NotifyTriggers.NEVER, 'no_action',
52 'some approval thing', False, approval_id=2)
53
54 self.fd_2 = tracker_bizobj.MakeFieldDef(
55 2, self.project.project_id, 'UXApproval',
56 tracker_pb2.FieldTypes.APPROVAL_TYPE, None, '', False, False, False,
57 None, None, '', False, '', '', tracker_pb2.NotifyTriggers.NEVER,
58 'no_action', 'Approval for UX review', False)
59 self.fd_3 = tracker_bizobj.MakeFieldDef(
60 3, self.project.project_id, 'TestApproval',
61 tracker_pb2.FieldTypes.APPROVAL_TYPE, None, '', False, False, False,
62 None, None, '', False, '', '', tracker_pb2.NotifyTriggers.NEVER,
63 'no_action', 'Approval for Test review', False)
64 self.fd_4 = tracker_bizobj.MakeFieldDef(
65 4, self.project.project_id, 'Target',
66 tracker_pb2.FieldTypes.INT_TYPE, None, '', False, False, False, None,
67 None, '', False, '', '', tracker_pb2.NotifyTriggers.NEVER, 'no_action',
68 'milestone target', False, is_phase_field=True)
69 self.fd_5 = tracker_bizobj.MakeFieldDef(
70 5,
71 self.project.project_id,
72 'RestrictedField',
73 tracker_pb2.FieldTypes.INT_TYPE,
74 None,
75 '',
76 False,
77 False,
78 False,
79 None,
80 None,
81 '',
82 False,
83 '',
84 '',
85 tracker_pb2.NotifyTriggers.NEVER,
86 'no_action',
87 'RestrictedField',
88 False,
89 is_restricted_field=True)
90 self.fd_6 = tracker_bizobj.MakeFieldDef(
91 6,
92 self.project.project_id,
93 'RestrictedEnumField',
94 tracker_pb2.FieldTypes.ENUM_TYPE,
95 None,
96 '',
97 False,
98 False,
99 False,
100 None,
101 None,
102 '',
103 False,
104 '',
105 '',
106 tracker_pb2.NotifyTriggers.NEVER,
107 'no_action',
108 'RestrictedEnumField',
109 False,
110 is_restricted_field=True)
111 ad_2 = tracker_pb2.ApprovalDef(approval_id=2)
112 ad_3 = tracker_pb2.ApprovalDef(approval_id=3)
113
114 self.config = self.services.config.GetProjectConfig(
115 'fake cnxn', self.project.project_id)
116 self.config.approval_defs.extend([ad_2, ad_3])
117 self.config.field_defs.extend(
118 [self.fd_1, self.fd_2, self.fd_3, self.fd_4, self.fd_5, self.fd_6])
119
120 first_tmpl = tracker_bizobj.MakeIssueTemplate(
121 'sometemplate', 'summary', None, None, 'content', [], [], [],
122 [])
123 self.services.config.StoreConfig(None, self.config)
124
125 templates = testing_helpers.DefaultTemplates()
126 templates.append(first_tmpl)
127 self.services.template.GetProjectTemplates = Mock(
128 return_value=templates)
129
130 self.mr = testing_helpers.MakeMonorailRequest(
131 project=self.project, perms=permissions.OWNER_ACTIVE_PERMISSIONSET)
132 self.mox = mox.Mox()
133
134 def tearDown(self):
135 self.mox.UnsetStubs()
136 self.mox.ResetAll()
137
138 def testAssertBasePermission(self):
139 # Anon users can never do it
140 self.mr.perms = permissions.READ_ONLY_PERMISSIONSET
141 self.assertRaises(
142 permissions.PermissionException,
143 self.servlet.AssertBasePermission, self.mr)
144
145 # Project owner can do it.
146 self.mr.perms = permissions.OWNER_ACTIVE_PERMISSIONSET
147 self.servlet.AssertBasePermission(self.mr)
148
149 # Project member cannot do it
150 self.mr.perms = permissions.COMMITTER_ACTIVE_PERMISSIONSET
151 self.assertRaises(
152 permissions.PermissionException,
153 self.servlet.AssertBasePermission, self.mr)
154 self.mr.perms = permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET
155 self.assertRaises(
156 permissions.PermissionException,
157 self.servlet.AssertBasePermission, self.mr)
158
159 def testGatherPageData(self):
160 precomp_view_info = tracker_views._PrecomputeInfoForValueViews(
161 [], [], [], self.config, [])
162 fv = tracker_views._MakeFieldValueView(
163 self.fd_1, self.config, precomp_view_info, {})
164 page_data = self.servlet.GatherPageData(self.mr)
165 self.assertEqual(self.servlet.PROCESS_TAB_TEMPLATES,
166 page_data['admin_tab_mode'])
167 self.assertTrue(page_data['allow_edit'])
168 self.assertEqual(page_data['uneditable_fields'], ezt.boolean(False))
169 self.assertTrue(page_data['new_template_form'])
170 self.assertFalse(page_data['initial_members_only'])
171 self.assertEqual(page_data['template_name'], '')
172 self.assertEqual(page_data['initial_summary'], '')
173 self.assertFalse(page_data['initial_must_edit_summary'])
174 self.assertEqual(page_data['initial_content'], '')
175 self.assertEqual(page_data['initial_status'], '')
176 self.assertEqual(page_data['initial_owner'], '')
177 self.assertFalse(page_data['initial_owner_defaults_to_member'])
178 self.assertEqual(page_data['initial_components'], '')
179 self.assertFalse(page_data['initial_component_required'])
180 self.assertEqual(page_data['fields'][2].field_name, fv.field_name)
181 self.assertEqual(page_data['initial_admins'], '')
182 self.assertEqual(page_data['approval_subfields_present'], ezt.boolean(True))
183 self.assertEqual(page_data['phase_fields_present'], ezt.boolean(False))
184
185 def testProcessFormData_Reject(self):
186 self.services.user.TestAddUser('user@example.com', 222)
187 self.mr.auth.effective_ids = {222}
188 post_data = fake.PostData(
189 name=['sometemplate'],
190 members_only=['on'],
191 summary=['TLDR'],
192 summary_must_be_edited=['on'],
193 content=['HEY WHY'],
194 status=['Accepted'],
195 owner=['someone@world.com'],
196 label=['label-One', 'label-Two'],
197 custom_1=['NO'],
198 custom_2=['MOOD'],
199 components=['hey, hey2,he3'],
200 component_required=['on'],
201 owner_defaults_to_member=['no'],
202 add_approvals = ['on'],
203 phase_0=['Canary'],
204 phase_1=['Stable-Exp'],
205 phase_2=['Stable'],
206 phase_3=[''],
207 phase_4=[''],
208 phase_5=[''],
209 approval_2=['phase_1'],
210 approval_3=['phase_2']
211 )
212
213 self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect')
214 self.servlet.PleaseCorrect(
215 self.mr,
216 initial_members_only=ezt.boolean(True),
217 template_name='sometemplate',
218 initial_content='TLDR',
219 initial_must_edit_summary=ezt.boolean(True),
220 initial_description='HEY WHY',
221 initial_status='Accepted',
222 initial_owner='someone@world.com',
223 initial_owner_defaults_to_member=ezt.boolean(False),
224 initial_components='hey, hey2, he3',
225 initial_component_required=ezt.boolean(True),
226 initial_admins='',
227 labels=['label-One', 'label-Two'],
228 fields=mox.IgnoreArg(),
229 initial_add_approvals=ezt.boolean(True),
230 initial_phases=[tracker_pb2.Phase(name=name) for
231 name in ['Canary', 'Stable-Exp', 'Stable', '', '', '']],
232 approvals=mox.IgnoreArg(),
233 prechecked_approvals=['2_phase_1', '3_phase_2'],
234 required_approval_ids=[]
235 )
236 self.mox.ReplayAll()
237 url = self.servlet.ProcessFormData(self.mr, post_data)
238 self.mox.VerifyAll()
239 self.assertEqual('Owner not found.', self.mr.errors.owner)
240 self.assertEqual('Unknown component he3', self.mr.errors.components)
241 self.assertEqual(
242 'Template with name sometemplate already exists', self.mr.errors.name)
243 self.assertEqual('Defined gates must have assigned approvals.',
244 self.mr.errors.phase_approvals)
245 self.assertIsNone(url)
246
247 def testProcessFormData_RejectRestrictedFields(self):
248 self.services.template.GetTemplateByName = Mock(return_value=None)
249 self.mr.perms = permissions.PermissionSet([])
250 post_data_add_fv = fake.PostData(
251 name=['secondtemplate'],
252 members_only=['on'],
253 summary=['TLDR'],
254 summary_must_be_edited=['on'],
255 content=['HEY WHY'],
256 status=['Accepted'],
257 label=['label-One', 'label-Two'],
258 custom_1=['Hey'],
259 custom_5=['7'],
260 component_required=['on'],
261 owner_defaults_to_member=['no'],
262 add_approvals=['no'],
263 phase_0=[''],
264 phase_1=[''],
265 phase_2=[''],
266 phase_3=[''],
267 phase_4=[''],
268 phase_5=['OOPs'],
269 approval_2=['phase_0'],
270 approval_3=['phase_2'])
271 post_data_label_edits_enum = fake.PostData(
272 name=['secondtemplate'],
273 members_only=['on'],
274 summary=['TLDR'],
275 summary_must_be_edited=['on'],
276 content=['HEY WHY'],
277 status=['Accepted'],
278 label=['label-One', 'label-Two', 'RestrictedEnumField-7'],
279 component_required=['on'],
280 owner_defaults_to_member=['no'],
281 add_approvals=['no'],
282 phase_0=[''],
283 phase_1=[''],
284 phase_2=[''],
285 phase_3=[''],
286 phase_4=[''],
287 phase_5=['OOPs'],
288 approval_2=['phase_0'],
289 approval_3=['phase_2'])
290
291 self.assertRaises(
292 AssertionError, self.servlet.ProcessFormData, self.mr, post_data_add_fv)
293 self.assertRaises(
294 AssertionError, self.servlet.ProcessFormData, self.mr,
295 post_data_label_edits_enum)
296
297 def testProcessFormData_Accept(self):
298 self.services.user.TestAddUser('user@example.com', 222)
299 self.mr.auth.effective_ids = {222}
300 self.services.template.GetTemplateByName = Mock(return_value=None)
301 post_data = fake.PostData(
302 name=['secondtemplate'],
303 members_only=['on'],
304 summary=['TLDR'],
305 summary_must_be_edited=['on'],
306 content=['HEY WHY'],
307 status=['Accepted'],
308 label=['label-One', 'label-Two', 'RestrictedEnumField-7'],
309 custom_1=['NO'],
310 custom_5=['37'],
311 component_required=['on'],
312 owner_defaults_to_member=['no'],
313 add_approvals=['no'],
314 phase_0=[''],
315 phase_1=[''],
316 phase_2=[''],
317 phase_3=[''],
318 phase_4=[''],
319 phase_5=['OOPs'],
320 approval_2=['phase_0'],
321 approval_3=['phase_2'])
322
323 url = self.servlet.ProcessFormData(self.mr, post_data)
324
325 self.assertTrue('/adminTemplates?saved=1&ts' in url)
326
327 self.assertEqual(0,
328 self.services.template.UpdateIssueTemplateDef.call_count)
329
330 # errors in phases should not matter if add_approvals is not 'on'
331 self.assertIsNone(self.mr.errors.phase_approvals)
332
333 def testProcessFormData_AcceptPhases(self):
334 self.services.user.TestAddUser('user@example.com', 222)
335 self.mr.auth.effective_ids = {222}
336 self.services.template.GetTemplateByName = Mock(return_value=None)
337 post_data = fake.PostData(
338 name=['secondtemplate'],
339 members_only=['on'],
340 summary=['TLDR'],
341 summary_must_be_edited=['on'],
342 content=['HEY WHY'],
343 status=['Accepted'],
344 label=['label-One', 'label-Two'],
345 custom_1=['NO'],
346 component_required=['on'],
347 owner_defaults_to_member=['no'],
348 add_approvals = ['on'],
349 phase_0=['Canary'],
350 phase_1=['Stable'],
351 phase_2=[''],
352 phase_3=[''],
353 phase_4=[''],
354 phase_5=[''],
355 approval_2=['phase_0'],
356 approval_3=['phase_1'],
357 approval_3_required=['on']
358 )
359
360 url = self.servlet.ProcessFormData(self.mr, post_data)
361 self.assertTrue('/adminTemplates?saved=1&ts' in url)
362
363 fv = tracker_pb2.FieldValue(field_id=1, str_value='NO', derived=False)
364 phases = [
365 tracker_pb2.Phase(name='Canary', rank=0, phase_id=0),
366 tracker_pb2.Phase(name='Stable', rank=1, phase_id=1)
367 ]
368 approval_values = [
369 tracker_pb2.ApprovalValue(approval_id=2, phase_id=0),
370 tracker_pb2.ApprovalValue(
371 approval_id=3, status=tracker_pb2.ApprovalStatus(
372 tracker_pb2.ApprovalStatus.NEEDS_REVIEW), phase_id=1)
373 ]
374 self.services.template.CreateIssueTemplateDef.assert_called_once_with(
375 self.mr.cnxn, 47925, 'secondtemplate', 'HEY WHY', 'TLDR', True,
376 'Accepted', True, False, True, 0, ['label-One', 'label-Two'], [], [],
377 [fv], phases=phases, approval_values=approval_values)