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