blob: 18886bcd3ca563776e5bdfe66151ac484960a9d5 [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"""Unit tests for the componentdetail servlet."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import unittest
12
13from mock import Mock, patch
14
15import mox
16
17from features import filterrules_helpers
18from framework import permissions
19from proto import project_pb2
20from services import service_manager
21from services import template_svc
22from testing import fake
23from testing import testing_helpers
24from tracker import componentdetail
25from tracker import tracker_bizobj
26
27import webapp2
28
29
30class ComponentDetailTest(unittest.TestCase):
31
32 def setUp(self):
33 self.services = service_manager.Services(
34 user=fake.UserService(),
35 issue=fake.IssueService(),
36 config=fake.ConfigService(),
37 template=Mock(spec=template_svc.TemplateService),
38 project=fake.ProjectService())
39 self.servlet = componentdetail.ComponentDetail(
40 'req', 'res', services=self.services)
41 self.project = self.services.project.TestAddProject('proj')
42 self.mr = testing_helpers.MakeMonorailRequest(
43 project=self.project, perms=permissions.OWNER_ACTIVE_PERMISSIONSET)
44 self.mr.auth.email = 'b@example.com'
45 self.config = self.services.config.GetProjectConfig(
46 'fake cnxn', self.project.project_id)
47 self.services.config.StoreConfig('fake cnxn', self.config)
48 self.cd = tracker_bizobj.MakeComponentDef(
49 1, self.project.project_id, 'BackEnd', 'doc', False, [], [111], 100000,
50 122, 10000000, 133)
51 self.config.component_defs = [self.cd]
52 self.services.user.TestAddUser('a@example.com', 111)
53 self.services.user.TestAddUser('b@example.com', 122)
54 self.services.user.TestAddUser('c@example.com', 133)
55 self.mr.component_path = 'BackEnd'
56
57 self.mox = mox.Mox()
58
59 def tearDown(self):
60 self.mox.UnsetStubs()
61 self.mox.ResetAll()
62
63 def testGetComponentDef_NotFound(self):
64 self.mr.component_path = 'NeverHeardOfIt'
65 self.assertRaises(
66 webapp2.HTTPException,
67 self.servlet._GetComponentDef, self.mr)
68
69 def testGetComponentDef_Normal(self):
70 actual_config, actual_cd = self.servlet._GetComponentDef(self.mr)
71 self.assertEqual(self.config, actual_config)
72 self.assertEqual(self.cd, actual_cd)
73
74 def testAssertBasePermission_AnyoneCanView(self):
75 self.servlet.AssertBasePermission(self.mr)
76 self.mr.perms = permissions.COMMITTER_ACTIVE_PERMISSIONSET
77 self.servlet.AssertBasePermission(self.mr)
78 self.mr.perms = permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET
79 self.servlet.AssertBasePermission(self.mr)
80 self.mr.perms = permissions.READ_ONLY_PERMISSIONSET
81 self.servlet.AssertBasePermission(self.mr)
82
83 def testAssertBasePermission_MembersOnly(self):
84 self.project.access = project_pb2.ProjectAccess.MEMBERS_ONLY
85 # The project members can view the component definition.
86 self.servlet.AssertBasePermission(self.mr)
87 self.mr.perms = permissions.COMMITTER_ACTIVE_PERMISSIONSET
88 self.servlet.AssertBasePermission(self.mr)
89 self.mr.perms = permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET
90 self.servlet.AssertBasePermission(self.mr)
91 # Non-member is not allowed to view anything in the project.
92 self.mr.perms = permissions.EMPTY_PERMISSIONSET
93 self.assertRaises(
94 permissions.PermissionException,
95 self.servlet.AssertBasePermission, self.mr)
96
97 def testGatherPageData_ReadWrite(self):
98 page_data = self.servlet.GatherPageData(self.mr)
99 self.assertEqual(self.servlet.PROCESS_TAB_COMPONENTS,
100 page_data['admin_tab_mode'])
101 self.assertTrue(page_data['allow_edit'])
102 self.assertEqual([], page_data['initial_admins'])
103 component_def_view = page_data['component_def']
104 self.assertEqual('BackEnd', component_def_view.path)
105
106 def testGatherPageData_ReadOnly(self):
107 self.mr.perms = permissions.READ_ONLY_PERMISSIONSET
108 page_data = self.servlet.GatherPageData(self.mr)
109 self.assertEqual(self.servlet.PROCESS_TAB_COMPONENTS,
110 page_data['admin_tab_mode'])
111 self.assertFalse(page_data['allow_edit'])
112 self.assertFalse(page_data['allow_delete'])
113 self.assertEqual([], page_data['initial_admins'])
114 component_def_view = page_data['component_def']
115 self.assertEqual('BackEnd', component_def_view.path)
116
117 def testGatherPageData_ObscuredCreatorModifier(self):
118 page_data = self.servlet.GatherPageData(self.mr)
119
120 self.assertEqual('b...@example.com', page_data['creator'].display_name)
121 self.assertEqual('/u/122/', page_data['creator'].profile_url)
122 self.assertEqual('Jan 1970', page_data['created'])
123 self.assertEqual('c...@example.com', page_data['modifier'].display_name)
124 self.assertEqual('/u/133/', page_data['modifier'].profile_url)
125 self.assertEqual('Apr 1970', page_data['modified'])
126
127 def testGatherPageData_VisibleCreatorModifierForAdmin(self):
128 self.mr.auth.user_pb.is_site_admin = True
129 page_data = self.servlet.GatherPageData(self.mr)
130
131 self.assertEqual('b@example.com', page_data['creator'].display_name)
132 self.assertEqual('/u/b@example.com/', page_data['creator'].profile_url)
133 self.assertEqual('Jan 1970', page_data['created'])
134 self.assertEqual('c@example.com', page_data['modifier'].display_name)
135 self.assertEqual('/u/c@example.com/', page_data['modifier'].profile_url)
136 self.assertEqual('Apr 1970', page_data['modified'])
137
138 def testGatherPageData_VisibleCreatorForSelf(self):
139 self.mr.auth.user_id = 122
140 page_data = self.servlet.GatherPageData(self.mr)
141
142 self.assertEqual('b@example.com', page_data['creator'].display_name)
143 self.assertEqual('/u/b@example.com/', page_data['creator'].profile_url)
144 self.assertEqual('Jan 1970', page_data['created'])
145 # Modifier should still be obscured.
146 self.assertEqual('c...@example.com', page_data['modifier'].display_name)
147 self.assertEqual('/u/133/', page_data['modifier'].profile_url)
148 self.assertEqual('Apr 1970', page_data['modified'])
149
150 def testGatherPageData_VisibleCreatorModifierForUnobscuredEmail(self):
151 creator = self.services.user.GetUser(self.mr.cnxn, 122)
152 creator.obscure_email = False
153 modifier = self.services.user.GetUser(self.mr.cnxn, 133)
154 modifier.obscure_email = False
155 page_data = self.servlet.GatherPageData(self.mr)
156
157 self.assertEqual('b@example.com', page_data['creator'].display_name)
158 self.assertEqual('/u/b@example.com/', page_data['creator'].profile_url)
159 self.assertEqual('Jan 1970', page_data['created'])
160 self.assertEqual('c@example.com', page_data['modifier'].display_name)
161 self.assertEqual('/u/c@example.com/', page_data['modifier'].profile_url)
162 self.assertEqual('Apr 1970', page_data['modified'])
163
164 def testGatherPageData_WithSubComponents(self):
165 subcd = tracker_bizobj.MakeComponentDef(
166 2, self.project.project_id, 'BackEnd>Worker', 'doc', False, [], [111],
167 0, 122)
168 self.config.component_defs.append(subcd)
169 page_data = self.servlet.GatherPageData(self.mr)
170 self.assertFalse(page_data['allow_delete'])
171 self.assertEqual([subcd], page_data['subcomponents'])
172
173 def testGatherPageData_WithTemplates(self):
174 self.services.template.TemplatesWithComponent.return_value = ['template']
175 page_data = self.servlet.GatherPageData(self.mr)
176 self.assertFalse(page_data['allow_delete'])
177 self.assertEqual(['template'], page_data['templates'])
178
179 def testProcessFormData_Permission(self):
180 """Only owners can edit components."""
181 mr = testing_helpers.MakeMonorailRequest(
182 project=self.project,
183 perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET)
184 mr.component_path = 'BackEnd'
185 post_data = fake.PostData(
186 name=['BackEnd'],
187 deletecomponent=['Submit'])
188 self.assertRaises(permissions.PermissionException,
189 self.servlet.ProcessFormData, mr, post_data)
190
191 self.servlet.ProcessFormData(self.mr, post_data)
192
193 def testProcessFormData_Delete(self):
194 post_data = fake.PostData(
195 name=['BackEnd'],
196 deletecomponent=['Submit'])
197 url = self.servlet.ProcessFormData(self.mr, post_data)
198 self.assertTrue('/adminComponents?deleted=1&' in url)
199 self.assertIsNone(
200 tracker_bizobj.FindComponentDef('BackEnd', self.config))
201
202 def testProcessFormData_Delete_WithSubComponent(self):
203 subcd = tracker_bizobj.MakeComponentDef(
204 2, self.project.project_id, 'BackEnd>Worker', 'doc', False, [], [111],
205 0, 122)
206 self.config.component_defs.append(subcd)
207
208 post_data = fake.PostData(
209 name=['BackEnd'],
210 deletecomponent=['Submit'])
211 with self.assertRaises(permissions.PermissionException) as cm:
212 self.servlet.ProcessFormData(self.mr, post_data)
213 self.assertEqual(
214 'User tried to delete component that had subcomponents',
215 cm.exception.message)
216
217 def testProcessFormData_Edit(self):
218 post_data = fake.PostData(
219 leaf_name=['BackEnd'],
220 docstring=['This is where the magic happens'],
221 deprecated=[True],
222 admins=['a@example.com'],
223 cc=['a@example.com'],
224 labels=['Hot, Cold'])
225
226 url = self.servlet.ProcessFormData(self.mr, post_data)
227
228 self.mox.VerifyAll()
229 self.assertTrue('/components/detail?component=BackEnd&saved=1&' in url)
230 config = self.services.config.GetProjectConfig(
231 self.mr.cnxn, self.mr.project_id)
232
233 cd = tracker_bizobj.FindComponentDef('BackEnd', config)
234 self.assertEqual('BackEnd', cd.path)
235 self.assertEqual(
236 'This is where the magic happens',
237 cd.docstring)
238 self.assertEqual(True, cd.deprecated)
239 self.assertEqual([111], cd.admin_ids)
240 self.assertEqual([111], cd.cc_ids)
241
242 def testProcessDeleteComponent(self):
243 self.servlet._ProcessDeleteComponent(self.mr, self.cd)
244 self.assertIsNone(
245 tracker_bizobj.FindComponentDef('BackEnd', self.config))
246
247 def testProcessEditComponent(self):
248 post_data = fake.PostData(
249 leaf_name=['BackEnd'],
250 docstring=['This is where the magic happens'],
251 deprecated=[True],
252 admins=['a@example.com'],
253 cc=['a@example.com'],
254 labels=['Hot, Cold'])
255
256 self.servlet._ProcessEditComponent(
257 self.mr, post_data, self.config, self.cd)
258
259 self.mox.VerifyAll()
260 config = self.services.config.GetProjectConfig(
261 self.mr.cnxn, self.mr.project_id)
262 cd = tracker_bizobj.FindComponentDef('BackEnd', config)
263 self.assertEqual('BackEnd', cd.path)
264 self.assertEqual(
265 'This is where the magic happens',
266 cd.docstring)
267 self.assertEqual(True, cd.deprecated)
268 self.assertEqual([111], cd.admin_ids)
269 self.assertEqual([111], cd.cc_ids)
270 # Assert that creator and created were not updated.
271 self.assertEqual(122, cd.creator_id)
272 self.assertEqual(100000, cd.created)
273 # Assert that modifier and modified were updated.
274 self.assertEqual(122, cd.modifier_id)
275 self.assertTrue(cd.modified > 10000000)
276
277 def testProcessEditComponent_RenameWithSubComponents(self):
278 subcd_1 = tracker_bizobj.MakeComponentDef(
279 2, self.project.project_id, 'BackEnd>Worker1', 'doc', False, [], [111],
280 0, 125, 3, 126)
281 subcd_2 = tracker_bizobj.MakeComponentDef(
282 3, self.project.project_id, 'BackEnd>Worker2', 'doc', False, [], [111],
283 0, 125, 4, 127)
284 self.config.component_defs.extend([subcd_1, subcd_2])
285
286 self.mox.StubOutWithMock(filterrules_helpers, 'RecomputeAllDerivedFields')
287 filterrules_helpers.RecomputeAllDerivedFields(
288 self.mr.cnxn, self.services, self.mr.project, self.config)
289 self.mox.ReplayAll()
290 post_data = fake.PostData(
291 leaf_name=['BackEnds'],
292 docstring=['This is where the magic happens'],
293 deprecated=[True],
294 admins=['a@example.com'],
295 cc=['a@example.com'],
296 labels=[''])
297
298 self.servlet._ProcessEditComponent(
299 self.mr, post_data, self.config, self.cd)
300
301 self.mox.VerifyAll()
302 config = self.services.config.GetProjectConfig(
303 self.mr.cnxn, self.mr.project_id)
304 cd = tracker_bizobj.FindComponentDef('BackEnds', config)
305 self.assertEqual('BackEnds', cd.path)
306 subcd_1 = tracker_bizobj.FindComponentDef('BackEnds>Worker1', config)
307 self.assertEqual('BackEnds>Worker1', subcd_1.path)
308 # Assert that creator and modifier have not changed for subcd_1.
309 self.assertEqual(125, subcd_1.creator_id)
310 self.assertEqual(0, subcd_1.created)
311 self.assertEqual(126, subcd_1.modifier_id)
312 self.assertEqual(3, subcd_1.modified)
313
314 subcd_2 = tracker_bizobj.FindComponentDef('BackEnds>Worker2', config)
315 self.assertEqual('BackEnds>Worker2', subcd_2.path)
316 # Assert that creator and modifier have not changed for subcd_2.
317 self.assertEqual(125, subcd_2.creator_id)
318 self.assertEqual(0, subcd_2.created)
319 self.assertEqual(127, subcd_2.modifier_id)
320 self.assertEqual(4, subcd_2.modified)