blob: e58f1ab90c4e55b4d3e729b2018c2d4b44bcd5e5 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2020 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"""Tests for the hotlists servicer."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import unittest
11
12from google.protobuf import timestamp_pb2
13from mock import patch
14
15from api import resource_name_converters as rnc
16from api.v3 import converters
17from api.v3 import frontend_servicer
18from api.v3.api_proto import frontend_pb2
19from api.v3.api_proto import project_objects_pb2
20from framework import exceptions
21from framework import monorailcontext
22from proto import tracker_pb2
23from services import service_manager
24from testing import fake
25from tracker import tracker_constants
26
27
28class FrontendServicerTest(unittest.TestCase):
29
30 def setUp(self):
31 self.cnxn = fake.MonorailConnection()
32 self.services = service_manager.Services(
33 features=fake.FeaturesService(),
34 issue=fake.IssueService(),
35 project=fake.ProjectService(),
36 config=fake.ConfigService(),
37 user=fake.UserService(),
38 template=fake.TemplateService(),
39 usergroup=fake.UserGroupService())
40 self.frontend_svcr = frontend_servicer.FrontendServicer(
41 self.services, make_rate_limiter=False)
42
43 self.user_1 = self.services.user.TestAddUser('user_111@example.com', 111)
44 self.user_1_resource_name = 'users/111'
45 self.project_1_resource_name = 'projects/proj'
46 self.project_1 = self.services.project.TestAddProject(
47 'proj', project_id=789)
48 self.template_0 = self.services.template.TestAddIssueTemplateDef(
49 11110, self.project_1.project_id, 'template0')
50 self.PAST_TIME = 12345
51 self.component_def_1_path = 'foo'
52 self.component_def_1_id = self.services.config.CreateComponentDef(
53 self.cnxn, self.project_1.project_id, self.component_def_1_path,
54 'cd1_docstring', False, [self.user_1.user_id], [], self.PAST_TIME,
55 self.user_1.user_id, [])
56 self.field_def_1_name = 'test_field_1'
57 self.field_def_1 = self._CreateFieldDef(
58 self.project_1.project_id,
59 self.field_def_1_name,
60 'STR_TYPE',
61 admin_ids=[self.user_1.user_id],
62 is_required=True,
63 is_multivalued=True,
64 is_phase_field=True,
65 regex='abc')
66 self.approval_def_1_name = 'approval_field_1'
67 self.approval_def_1_id = self._CreateFieldDef(
68 self.project_1.project_id,
69 self.approval_def_1_name,
70 'APPROVAL_TYPE',
71 docstring='ad_1_docstring',
72 admin_ids=[self.user_1.user_id])
73 self.approval_def_1 = tracker_pb2.ApprovalDef(
74 approval_id=self.approval_def_1_id,
75 approver_ids=[self.user_1.user_id],
76 survey='approval_def_1 survey')
77 self.services.config.UpdateConfig(
78 self.cnxn,
79 self.project_1,
80 # UpdateConfig accepts tuples rather than protorpc *Defs
81 approval_defs=[
82 (ad.approval_id, ad.approver_ids, ad.survey)
83 for ad in [self.approval_def_1]
84 ])
85
86 def _CreateFieldDef(
87 self,
88 project_id,
89 field_name,
90 field_type_str,
91 docstring=None,
92 min_value=None,
93 max_value=None,
94 regex=None,
95 needs_member=None,
96 needs_perm=None,
97 grants_perm=None,
98 notify_on=None,
99 date_action_str=None,
100 admin_ids=None,
101 editor_ids=None,
102 is_required=False,
103 is_niche=False,
104 is_multivalued=False,
105 is_phase_field=False,
106 approval_id=None,
107 is_restricted_field=False):
108 """Calls CreateFieldDef with reasonable defaults, returns the ID."""
109 if admin_ids is None:
110 admin_ids = []
111 if editor_ids is None:
112 editor_ids = []
113 return self.services.config.CreateFieldDef(
114 self.cnxn,
115 project_id,
116 field_name,
117 field_type_str,
118 None,
119 None,
120 is_required,
121 is_niche,
122 is_multivalued,
123 min_value,
124 max_value,
125 regex,
126 needs_member,
127 needs_perm,
128 grants_perm,
129 notify_on,
130 date_action_str,
131 docstring,
132 admin_ids,
133 editor_ids,
134 is_phase_field=is_phase_field,
135 approval_id=approval_id,
136 is_restricted_field=is_restricted_field)
137
138 def CallWrapped(self, wrapped_handler, mc, *args, **kwargs):
139 self.frontend_svcr.converter = converters.Converter(mc, self.services)
140 return wrapped_handler.wrapped(self.frontend_svcr, mc, *args, **kwargs)
141
142 @patch('project.project_helpers.GetThumbnailUrl')
143 def testGatherProjectEnvironment(self, mock_GetThumbnailUrl):
144 """We can fetch all project related parameters for web frontend."""
145 mock_GetThumbnailUrl.return_value = 'xyz'
146
147 request = frontend_pb2.GatherProjectEnvironmentRequest(
148 parent=self.project_1_resource_name)
149 mc = monorailcontext.MonorailContext(
150 self.services, cnxn=self.cnxn, requester=self.user_1.email)
151 response = self.CallWrapped(
152 self.frontend_svcr.GatherProjectEnvironment, mc, request)
153 project_config = self.services.config.GetProjectConfig(
154 self.cnxn, self.project_1.project_id)
155
156 self.assertEqual(
157 response.project,
158 self.frontend_svcr.converter.ConvertProject(self.project_1))
159 self.assertEqual(
160 response.project_config,
161 self.frontend_svcr.converter.ConvertProjectConfig(project_config))
162
163 self.assertEqual(
164 len(response.statuses),
165 len(tracker_constants.DEFAULT_WELL_KNOWN_STATUSES))
166 self.assertEqual(
167 response.statuses[0],
168 project_objects_pb2.StatusDef(
169 name='projects/{project_name}/statusDefs/{status}'.format(
170 project_name=self.project_1.project_name,
171 status=tracker_constants.DEFAULT_WELL_KNOWN_STATUSES[0][0]),
172 value=tracker_constants.DEFAULT_WELL_KNOWN_STATUSES[0][0],
173 type=project_objects_pb2.StatusDef.StatusDefType.Value('OPEN'),
174 rank=0,
175 docstring=tracker_constants.DEFAULT_WELL_KNOWN_STATUSES[0][1],
176 state=project_objects_pb2.StatusDef.StatusDefState.Value('ACTIVE'),
177 ))
178
179 self.assertEqual(
180 len(response.well_known_labels),
181 len(tracker_constants.DEFAULT_WELL_KNOWN_LABELS))
182 self.assertEqual(
183 response.well_known_labels[0],
184 project_objects_pb2.LabelDef(
185 name='projects/{project_name}/labelDefs/{label}'.format(
186 project_name=self.project_1.project_name,
187 label=tracker_constants.DEFAULT_WELL_KNOWN_LABELS[0][0]),
188 value=tracker_constants.DEFAULT_WELL_KNOWN_LABELS[0][0],
189 docstring=tracker_constants.DEFAULT_WELL_KNOWN_LABELS[0][1],
190 state=project_objects_pb2.LabelDef.LabelDefState.Value('ACTIVE'),
191 ))
192
193 expected = self.frontend_svcr.converter.ConvertComponentDefs(
194 project_config.component_defs, self.project_1.project_id)
195 # Have to use list comprehension to break response sub field into list
196 self.assertEqual([api_cd for api_cd in response.components], expected)
197
198 expected = self.frontend_svcr.converter.ConvertFieldDefs(
199 project_config.field_defs, self.project_1.project_id)
200 self.assertEqual([api_fd for api_fd in response.fields], expected)
201
202 expected = self.frontend_svcr.converter.ConvertApprovalDefs(
203 project_config.approval_defs, self.project_1.project_id)
204 self.assertEqual([api_ad for api_ad in response.approval_fields], expected)
205
206 def testGatherProjectMembershipsForUser(self):
207 """We can list a user's project memberships."""
208 self.services.project.TestAddProject(
209 'owner_proj', project_id=777, owner_ids=[111])
210 self.services.project.TestAddProject(
211 'committer_proj', project_id=888, committer_ids=[111])
212 contributor_proj = self.services.project.TestAddProject(
213 'contributor_proj', project_id=999)
214 contributor_proj.contributor_ids = [111]
215
216 request = frontend_pb2.GatherProjectMembershipsForUserRequest(
217 user=self.user_1_resource_name)
218 mc = monorailcontext.MonorailContext(
219 self.services, cnxn=self.cnxn, requester=self.user_1.email)
220 response = self.CallWrapped(
221 self.frontend_svcr.GatherProjectMembershipsForUser, mc, request)
222
223 owner_membership = project_objects_pb2.ProjectMember(
224 name='projects/{}/members/{}'.format('owner_proj', '111'),
225 role=project_objects_pb2.ProjectMember.ProjectRole.Value('OWNER'))
226 committer_membership = project_objects_pb2.ProjectMember(
227 name='projects/{}/members/{}'.format('committer_proj', '111'),
228 role=project_objects_pb2.ProjectMember.ProjectRole.Value('COMMITTER'))
229 contributor_membership = project_objects_pb2.ProjectMember(
230 name='projects/{}/members/{}'.format('contributor_proj', '111'),
231 role=project_objects_pb2.ProjectMember.ProjectRole.Value('CONTRIBUTOR'))
232 self.assertEqual(
233 response,
234 frontend_pb2.GatherProjectMembershipsForUserResponse(
235 project_memberships=[
236 owner_membership, committer_membership, contributor_membership
237 ]))