blob: 83aa8ab2aea6c9717c2f23c77824c8a5f2d87464 [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
11import mock
12import logging
13
14from google.protobuf import timestamp_pb2
15from google.protobuf import empty_pb2
16
17from api import resource_name_converters as rnc
18from api.v3 import projects_servicer
19from api.v3 import converters
20from api.v3.api_proto import projects_pb2
21from api.v3.api_proto import project_objects_pb2
22from api.v3.api_proto import issue_objects_pb2
23from framework import exceptions
24from framework import monorailcontext
25from framework import permissions
26from testing import fake
27from services import service_manager
28
29from google.appengine.ext import testbed
30
31class ProjectsServicerTest(unittest.TestCase):
32
33 def setUp(self):
34 # memcache and datastore needed for generating page tokens.
35 self.testbed = testbed.Testbed()
36 self.testbed.activate()
37 self.testbed.init_memcache_stub()
38 self.testbed.init_datastore_v3_stub()
39
40 self.cnxn = fake.MonorailConnection()
41 self.services = service_manager.Services(
42 features=fake.FeaturesService(),
43 issue=fake.IssueService(),
44 project=fake.ProjectService(),
45 config=fake.ConfigService(),
46 user=fake.UserService(),
47 template=fake.TemplateService(),
48 usergroup=fake.UserGroupService())
49 self.projects_svcr = projects_servicer.ProjectsServicer(
50 self.services, make_rate_limiter=False)
51
52 self.user_1 = self.services.user.TestAddUser('user_111@example.com', 111)
53
54 self.project_1 = self.services.project.TestAddProject(
55 'proj', project_id=789)
56 self.template_1 = self.services.template.TestAddIssueTemplateDef(
57 123, 789, 'template_1_name', content='foo bar', summary='foo')
58 self.project_1_resource_name = 'projects/proj'
59 self.converter = None
60
61 def CallWrapped(self, wrapped_handler, mc, *args, **kwargs):
62 self.converter = converters.Converter(mc, self.services)
63 self.projects_svcr.converter = self.converter
64 return wrapped_handler.wrapped(self.projects_svcr, mc, *args, **kwargs)
65
66 def testListIssueTemplates(self):
67 request = projects_pb2.ListIssueTemplatesRequest(
68 parent=self.project_1_resource_name)
69 mc = monorailcontext.MonorailContext(
70 self.services, cnxn=self.cnxn, requester=self.user_1.email)
71 response = self.CallWrapped(
72 self.projects_svcr.ListIssueTemplates, mc, request)
73
74 expected_issue = issue_objects_pb2.Issue(
75 summary=self.template_1.summary,
76 state=issue_objects_pb2.IssueContentState.Value('ACTIVE'),
77 status=issue_objects_pb2.Issue.StatusValue(
78 status=self.template_1.status,
79 derivation=issue_objects_pb2.Derivation.Value('EXPLICIT')))
80 expected_template = project_objects_pb2.IssueTemplate(
81 name='projects/{}/templates/{}'.format(
82 self.project_1.project_name, self.template_1.template_id),
83 display_name=self.template_1.name,
84 issue=expected_issue,
85 summary_must_be_edited=False,
86 template_privacy=project_objects_pb2.IssueTemplate.TemplatePrivacy
87 .Value('PUBLIC'),
88 default_owner=project_objects_pb2.IssueTemplate.DefaultOwner.Value(
89 'DEFAULT_OWNER_UNSPECIFIED'),
90 component_required=False)
91
92 self.assertEqual(
93 response,
94 projects_pb2.ListIssueTemplatesResponse(templates=[expected_template]))
95
96 @mock.patch('api.v3.api_constants.MAX_COMPONENTS_PER_PAGE', 3)
97 def testListComponentDefs(self):
98 project = self.services.project.TestAddProject(
99 'greece', project_id=987, owner_ids=[self.user_1.user_id])
100 config = fake.MakeTestConfig(project.project_id, [], [])
101 cd_1 = fake.MakeTestComponentDef(project.project_id, 1, path='Circe')
102 cd_2 = fake.MakeTestComponentDef(project.project_id, 2, path='Achilles')
103 cd_3 = fake.MakeTestComponentDef(project.project_id, 3, path='Patroclus')
104 cd_4 = fake.MakeTestComponentDef(project.project_id, 3, path='Galatea')
105 config.component_defs = [cd_1, cd_2, cd_3, cd_4]
106 self.services.config.StoreConfig(self.cnxn, config)
107
108 mc = monorailcontext.MonorailContext(
109 self.services, cnxn=self.cnxn, requester=self.user_1.email)
110
111 request = projects_pb2.ListComponentDefsRequest(parent='projects/greece')
112 response_1 = self.CallWrapped(
113 self.projects_svcr.ListComponentDefs, mc, request)
114 expected_cds_1 = self.converter.ConvertComponentDefs(
115 [cd_1, cd_2, cd_3], project.project_id)
116 self.assertEqual(list(response_1.component_defs), expected_cds_1)
117
118 request = projects_pb2.ListComponentDefsRequest(
119 parent='projects/greece', page_token=response_1.next_page_token)
120 response_2 = self.CallWrapped(
121 self.projects_svcr.ListComponentDefs, mc, request)
122 expected_cds_2 = self.converter.ConvertComponentDefs(
123 [cd_4], project.project_id)
124 self.assertEqual(list(response_2.component_defs), expected_cds_2)
125
126 @mock.patch('api.v3.api_constants.MAX_COMPONENTS_PER_PAGE', 2)
127 def testListComponentDefs_PaginateAndMaxSizeCap(self):
128 project = self.services.project.TestAddProject(
129 'greece', project_id=987, owner_ids=[self.user_1.user_id])
130 config = fake.MakeTestConfig(project.project_id, [], [])
131 cd_1 = fake.MakeTestComponentDef(project.project_id, 1, path='Circe')
132 cd_2 = fake.MakeTestComponentDef(project.project_id, 2, path='Achilles')
133 cd_3 = fake.MakeTestComponentDef(project.project_id, 3, path='Patroclus')
134 cd_4 = fake.MakeTestComponentDef(project.project_id, 4, path='Galatea')
135 cd_5 = fake.MakeTestComponentDef(project.project_id, 5, path='Briseis')
136 config.component_defs = [cd_1, cd_2, cd_3, cd_4, cd_5]
137 self.services.config.StoreConfig(self.cnxn, config)
138
139 mc = monorailcontext.MonorailContext(
140 self.services, cnxn=self.cnxn, requester=self.user_1.email)
141
142 request = projects_pb2.ListComponentDefsRequest(
143 parent='projects/greece', page_size=3)
144 response_1 = self.CallWrapped(
145 self.projects_svcr.ListComponentDefs, mc, request)
146 expected_cds_1 = self.converter.ConvertComponentDefs(
147 [cd_1, cd_2], project.project_id)
148 self.assertEqual(list(response_1.component_defs), expected_cds_1)
149
150 request = projects_pb2.ListComponentDefsRequest(
151 parent='projects/greece', page_size=3,
152 page_token=response_1.next_page_token)
153 response_2 = self.CallWrapped(
154 self.projects_svcr.ListComponentDefs, mc, request)
155 expected_cds_2 = self.converter.ConvertComponentDefs(
156 [cd_3, cd_4], project.project_id)
157 self.assertEqual(list(response_2.component_defs), expected_cds_2)
158
159 request = projects_pb2.ListComponentDefsRequest(
160 parent='projects/greece', page_size=3,
161 page_token=response_2.next_page_token)
162 response_3 = self.CallWrapped(
163 self.projects_svcr.ListComponentDefs, mc, request)
164 expected_cds_3 = self.converter.ConvertComponentDefs(
165 [cd_5], project.project_id)
166 self.assertEqual(response_3, projects_pb2.ListComponentDefsResponse(
167 component_defs=expected_cds_3))
168
169 @mock.patch('time.time')
170 def testCreateComponentDef(self, mockTime):
171 now = 123
172 mockTime.return_value = now
173
174 user_1 = self.services.user.TestAddUser('achilles@test.com', 981)
175 self.services.user.TestAddUser('patroclus@test.com', 982)
176 self.services.user.TestAddUser('circe@test.com', 983)
177
178 project = self.services.project.TestAddProject(
179 'chicken', project_id=987, owner_ids=[user_1.user_id])
180 config = fake.MakeTestConfig(project.project_id, [], [])
181 self.services.config.StoreConfig(self.cnxn, config)
182
183 expected = project_objects_pb2.ComponentDef(
184 value='circe',
185 docstring='You threw me to the crows',
186 admins=['users/983'],
187 ccs=['users/981', 'users/982'],
188 labels=['more-soup', 'beach-day'],
189 )
190 request = projects_pb2.CreateComponentDefRequest(
191 parent='projects/chicken', component_def=expected)
192 mc = monorailcontext.MonorailContext(
193 self.services, cnxn=self.cnxn, requester=user_1.email)
194 response = self.CallWrapped(
195 self.projects_svcr.CreateComponentDef, mc, request)
196
197 self.assertEqual(1, len(config.component_defs))
198 expected.name = 'projects/chicken/componentDefs/%d' % config.component_defs[
199 0].component_id
200 expected.state = project_objects_pb2.ComponentDef.ComponentDefState.Value(
201 'ACTIVE')
202 expected.creator = 'users/981'
203 expected.create_time.FromSeconds(now)
204 expected.modify_time.FromSeconds(0)
205 self.assertEqual(response, expected)
206
207 def testDeleteComponentDef(self):
208 user_1 = self.services.user.TestAddUser('achilles@test.com', 981)
209 project = self.services.project.TestAddProject(
210 'chicken', project_id=987, owner_ids=[user_1.user_id])
211 config = fake.MakeTestConfig(project.project_id, [], [])
212 component_def = fake.MakeTestComponentDef(
213 project.project_id, 1, path='Chickens>Dickens')
214 config.component_defs = [component_def]
215 self.services.config.StoreConfig(self.cnxn, config)
216
217 request = projects_pb2.DeleteComponentDefRequest(
218 name='projects/chicken/componentDefs/1')
219 mc = monorailcontext.MonorailContext(
220 self.services, cnxn=self.cnxn, requester=user_1.email)
221 actual = self.CallWrapped(
222 self.projects_svcr.DeleteComponentDef, mc, request)
223 self.assertEqual(actual, empty_pb2.Empty())
224
225 self.assertEqual(config.component_defs, [])
226
227 @mock.patch('project.project_helpers.GetThumbnailUrl')
228 def testListProjects(self, mock_GetThumbnailUrl):
229 mock_GetThumbnailUrl.return_value = 'xyz'
230
231 request = projects_pb2.ListProjectsRequest()
232
233 mc = monorailcontext.MonorailContext(
234 self.services, cnxn=self.cnxn, requester=self.user_1.email)
235 response = self.CallWrapped(self.projects_svcr.ListProjects, mc, request)
236
237 expected_project = project_objects_pb2.Project(
238 name=self.project_1_resource_name,
239 display_name=self.project_1.project_name,
240 summary=self.project_1.summary,
241 thumbnail_url='xyz')
242
243 self.assertEqual(
244 response,
245 projects_pb2.ListProjectsResponse(projects=[expected_project]))