blob: 892e2ce6b79f600425f08eb7b1322d07c7fdf3fa [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2018 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""Tests for the users servicer."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010010import pytest
11import six
Copybara854996b2021-09-07 19:36:02 +000012import unittest
13
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +020014try:
15 from mox3 import mox
16except ImportError:
17 import mox
Copybara854996b2021-09-07 19:36:02 +000018from components.prpc import codes
19from components.prpc import context
Copybara854996b2021-09-07 19:36:02 +000020
21from api import users_servicer
22from api.api_proto import common_pb2
23from api.api_proto import users_pb2
24from api.api_proto import user_objects_pb2
25from framework import authdata
26from framework import exceptions
27from framework import monorailcontext
28from framework import permissions
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010029from mrproto import project_pb2
30from mrproto import tracker_pb2
31from mrproto import user_pb2
Copybara854996b2021-09-07 19:36:02 +000032from testing import fake
33from services import service_manager
34
35
36class UsersServicerTest(unittest.TestCase):
37
38 def setUp(self):
39 self.mox = mox.Mox()
40 self.cnxn = fake.MonorailConnection()
41 self.services = service_manager.Services(
42 config=fake.ConfigService(),
43 issue=fake.IssueService(),
44 user=fake.UserService(),
45 user_star=fake.UserStarService(),
46 usergroup=fake.UserGroupService(),
47 project=fake.ProjectService(),
48 project_star=fake.ProjectStarService(),
49 features=fake.FeaturesService())
50 self.project = self.services.project.TestAddProject('proj', project_id=987)
51 self.user = self.services.user.TestAddUser('owner@example.com', 111)
52 self.user_2 = self.services.user.TestAddUser('test2@example.com', 222)
53 self.group1_id = self.services.usergroup.CreateGroup(
54 self.cnxn, self.services, 'group1@test.com', 'anyone')
55 self.group2_id = self.services.usergroup.CreateGroup(
56 self.cnxn, self.services, 'group2@test.com', 'anyone')
57 self.services.usergroup.UpdateMembers(
58 self.cnxn, self.group1_id, [111], 'member')
59 self.services.usergroup.UpdateMembers(
60 self.cnxn, self.group2_id, [222, 111], 'owner')
61 self.users_svcr = users_servicer.UsersServicer(
62 self.services, make_rate_limiter=False)
63 self.prpc_context = context.ServicerContext()
64 self.prpc_context.set_code(codes.StatusCode.OK)
65
66 def tearDown(self):
67 self.mox.UnsetStubs()
68 self.mox.ResetAll()
69
70 def CallWrapped(self, wrapped_handler, *args, **kwargs):
71 return wrapped_handler.wrapped(self.users_svcr, *args, **kwargs)
72
73 def testGetMemberships(self):
74 request = users_pb2.GetMembershipsRequest(
75 user_ref=common_pb2.UserRef(
76 display_name='owner@example.com', user_id=111))
77 mc = monorailcontext.MonorailContext(
78 self.services, cnxn=self.cnxn, requester='owner@example.com')
79
80 response = self.CallWrapped(self.users_svcr.GetMemberships, mc, request)
81 expected_group_refs = [
82 common_pb2.UserRef(
83 display_name='group1@test.com', user_id=self.group1_id),
84 common_pb2.UserRef(
85 display_name='group2@test.com', user_id=self.group2_id)
86 ]
87
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010088 six.assertCountEqual(self, expected_group_refs, response.group_refs)
Copybara854996b2021-09-07 19:36:02 +000089
90 def testGetMemberships_NonExistentUser(self):
91 request = users_pb2.GetMembershipsRequest(
92 user_ref=common_pb2.UserRef(
93 display_name='ghost@example.com', user_id=888)
94 )
95
96 mc = monorailcontext.MonorailContext(
97 self.services, cnxn=self.cnxn, requester='')
98
99 with self.assertRaises(exceptions.NoSuchUserException):
100 self.CallWrapped(self.users_svcr.GetMemberships, mc, request)
101
102 def testGetUser(self):
103 """We can get a user by email address."""
104 user_ref = common_pb2.UserRef(display_name='test2@example.com')
105 request = users_pb2.GetUserRequest(user_ref=user_ref)
106 mc = monorailcontext.MonorailContext(
107 self.services, cnxn=self.cnxn, requester='owner@example.com')
108 response = self.CallWrapped(
109 self.users_svcr.GetUser, mc, request)
110 self.assertEqual(response.display_name, 'test2@example.com')
111 self.assertEqual(response.user_id, 222)
112 self.assertFalse(response.is_site_admin)
113
114 self.user_2.is_site_admin = True
115 response = self.CallWrapped(
116 self.users_svcr.GetUser, mc, request)
117 self.assertTrue(response.is_site_admin)
118
119 def testListReferencedUsers(self):
120 """We can get all valid users by email addresses."""
121 request = users_pb2.ListReferencedUsersRequest(
122 # we ignore emails that are empty or belong to non-existent users.
123 user_refs=[
124 common_pb2.UserRef(display_name='test2@example.com'),
125 common_pb2.UserRef(display_name='ghost@example.com'),
126 common_pb2.UserRef(display_name=''),
127 common_pb2.UserRef()])
128 mc = monorailcontext.MonorailContext(
129 self.services, cnxn=self.cnxn, requester='owner@example.com')
130 response = self.CallWrapped(
131 self.users_svcr.ListReferencedUsers, mc, request)
132 self.assertEqual(len(response.users), 1)
133 self.assertEqual(response.users[0].user_id, 222)
134
135 def testListReferencedUsers_Deprecated(self):
136 """We can get all valid users by email addresses."""
137 request = users_pb2.ListReferencedUsersRequest(
138 # we ignore emails that are empty or belong to non-existent users.
139 emails=[
140 'test2@example.com',
141 'ghost@example.com',
142 ''])
143 mc = monorailcontext.MonorailContext(
144 self.services, cnxn=self.cnxn, requester='owner@example.com')
145 response = self.CallWrapped(
146 self.users_svcr.ListReferencedUsers, mc, request)
147 self.assertEqual(len(response.users), 1)
148 self.assertEqual(response.users[0].user_id, 222)
149
150 def CallGetStarCount(self):
151 request = users_pb2.GetUserStarCountRequest(
152 user_ref=common_pb2.UserRef(user_id=222))
153 mc = monorailcontext.MonorailContext(
154 self.services, cnxn=self.cnxn, requester='owner@example.com')
155 response = self.CallWrapped(
156 self.users_svcr.GetUserStarCount, mc, request)
157 return response.star_count
158
159 def CallStar(self, requester='owner@example.com', starred=True):
160 request = users_pb2.StarUserRequest(
161 user_ref=common_pb2.UserRef(user_id=222), starred=starred)
162 mc = monorailcontext.MonorailContext(
163 self.services, cnxn=self.cnxn, requester=requester)
164 response = self.CallWrapped(
165 self.users_svcr.StarUser, mc, request)
166 return response.star_count
167
168 def testStarCount_Normal(self):
169 self.assertEqual(0, self.CallGetStarCount())
170 self.assertEqual(1, self.CallStar())
171 self.assertEqual(1, self.CallGetStarCount())
172
173 def testStarCount_StarTwiceSameUser(self):
174 self.assertEqual(1, self.CallStar())
175 self.assertEqual(1, self.CallStar())
176 self.assertEqual(1, self.CallGetStarCount())
177
178 def testStarCount_StarTwiceDifferentUser(self):
179 self.assertEqual(1, self.CallStar())
180 self.assertEqual(2, self.CallStar(requester='test2@example.com'))
181 self.assertEqual(2, self.CallGetStarCount())
182
183 def testStarCount_RemoveStarTwiceSameUser(self):
184 self.assertEqual(1, self.CallStar())
185 self.assertEqual(1, self.CallGetStarCount())
186
187 self.assertEqual(0, self.CallStar(starred=False))
188 self.assertEqual(0, self.CallStar(starred=False))
189 self.assertEqual(0, self.CallGetStarCount())
190
191 def testStarCount_RemoveStarTwiceDifferentUser(self):
192 self.assertEqual(1, self.CallStar())
193 self.assertEqual(2, self.CallStar(requester='test2@example.com'))
194 self.assertEqual(2, self.CallGetStarCount())
195
196 self.assertEqual(1, self.CallStar(starred=False))
197 self.assertEqual(
198 0, self.CallStar(requester='test2@example.com', starred=False))
199 self.assertEqual(0, self.CallGetStarCount())
200
201 def testSetExpandPermsPreference_KeepOpen(self):
202 request = users_pb2.SetExpandPermsPreferenceRequest(expand_perms=True)
203 mc = monorailcontext.MonorailContext(
204 self.services, cnxn=self.cnxn, requester='owner@example.com')
205 self.CallWrapped(self.users_svcr.SetExpandPermsPreference, mc, request)
206
207 user = self.services.user.GetUser(self.cnxn, self.user.user_id)
208 self.assertTrue(user.keep_people_perms_open)
209
210 def testSetExpandPermsPreference_DontKeepOpen(self):
211 request = users_pb2.SetExpandPermsPreferenceRequest(expand_perms=False)
212 mc = monorailcontext.MonorailContext(
213 self.services, cnxn=self.cnxn, requester='owner@example.com')
214 self.CallWrapped(self.users_svcr.SetExpandPermsPreference, mc, request)
215
216 user = self.services.user.GetUser(self.cnxn, self.user.user_id)
217 self.assertFalse(user.keep_people_perms_open)
218
219 def testGetUserSavedQueries_Anon(self):
220 """Anon has empty saved queries."""
221 request = users_pb2.GetSavedQueriesRequest()
222 mc = monorailcontext.MonorailContext(
223 self.services, cnxn=self.cnxn, requester=None)
224 response = self.CallWrapped(self.users_svcr.GetSavedQueries, mc, request)
225
226 self.assertEqual(0, len(response.saved_queries))
227
228 def testGetUserSavedQueries_Mine(self):
229 """See your own queries."""
230 self.services.features.UpdateUserSavedQueries(self.cnxn, 111, [
231 tracker_pb2.SavedQuery(query_id=101, name='test', query='owner:me'),
232 tracker_pb2.SavedQuery(query_id=202, name='hello', query='world',
233 executes_in_project_ids=[987])
234 ])
235 request = users_pb2.GetUserPrefsRequest()
236 mc = monorailcontext.MonorailContext(
237 self.services, cnxn=self.cnxn, requester='owner@example.com')
238 response = self.CallWrapped(self.users_svcr.GetSavedQueries, mc, request)
239
240 self.assertEqual(2, len(response.saved_queries))
241
242 self.assertEqual('test', response.saved_queries[0].name)
243 self.assertEqual('owner:me', response.saved_queries[0].query)
244 self.assertEqual('hello', response.saved_queries[1].name)
245 self.assertEqual('world', response.saved_queries[1].query)
246 self.assertEqual(['proj'], response.saved_queries[1].project_names)
247
248
249 def testGetUserSavedQueries_Other_Allowed(self):
250 """See other people's queries if you're an admin."""
251 self.services.features.UpdateUserSavedQueries(self.cnxn, 111, [
252 tracker_pb2.SavedQuery(query_id=101, name='test', query='owner:me'),
253 tracker_pb2.SavedQuery(query_id=202, name='hello', query='world',
254 executes_in_project_ids=[987])
255 ])
256 self.user_2.is_site_admin = True
257
258 request = users_pb2.GetSavedQueriesRequest()
259 request.user_ref.display_name = 'owner@example.com'
260
261 mc = monorailcontext.MonorailContext(
262 self.services, cnxn=self.cnxn, requester='test2@example.com')
263
264 response = self.CallWrapped(self.users_svcr.GetSavedQueries, mc, request)
265
266 self.assertEqual(2, len(response.saved_queries))
267
268 self.assertEqual('test', response.saved_queries[0].name)
269 self.assertEqual('owner:me', response.saved_queries[0].query)
270 self.assertEqual('hello', response.saved_queries[1].name)
271 self.assertEqual('world', response.saved_queries[1].query)
272 self.assertEqual(['proj'], response.saved_queries[1].project_names)
273
274 def testGetUserSavedQueries_Other_Denied(self):
275 """Can't see other people's queries unless you're an admin."""
276 self.services.features.UpdateUserSavedQueries(self.cnxn, 111, [
277 tracker_pb2.SavedQuery(query_id=101, name='test', query='owner:me'),
278 tracker_pb2.SavedQuery(query_id=202, name='hello', query='world',
279 executes_in_project_ids=[987])
280 ])
281
282 request = users_pb2.GetSavedQueriesRequest()
283 request.user_ref.display_name = 'owner@example.com'
284
285 mc = monorailcontext.MonorailContext(
286 self.services, cnxn=self.cnxn, requester='test2@example.com')
287
288 with self.assertRaises(permissions.PermissionException):
289 self.CallWrapped(self.users_svcr.GetSavedQueries, mc, request)
290
291 def testGetUserPrefs_Anon(self):
292 """Anon always has empty prefs."""
293 request = users_pb2.GetUserPrefsRequest()
294 mc = monorailcontext.MonorailContext(
295 self.services, cnxn=self.cnxn, requester=None)
296 response = self.CallWrapped(self.users_svcr.GetUserPrefs, mc, request)
297
298 self.assertEqual(0, len(response.prefs))
299
300 def testGetUserPrefs_Mine_Empty(self):
301 """User who never set any pref gets empty prefs."""
302 request = users_pb2.GetUserPrefsRequest()
303 mc = monorailcontext.MonorailContext(
304 self.services, cnxn=self.cnxn, requester='owner@example.com')
305 response = self.CallWrapped(self.users_svcr.GetUserPrefs, mc, request)
306
307 self.assertEqual(0, len(response.prefs))
308
309 def testGetUserPrefs_Mine_Some(self):
310 """User who set a pref gets it back."""
311 self.services.user.SetUserPrefs(
312 self.cnxn, 111,
313 [user_pb2.UserPrefValue(name='code_font', value='true')])
314 request = users_pb2.GetUserPrefsRequest()
315 mc = monorailcontext.MonorailContext(
316 self.services, cnxn=self.cnxn, requester='owner@example.com')
317 response = self.CallWrapped(self.users_svcr.GetUserPrefs, mc, request)
318
319 self.assertEqual(1, len(response.prefs))
320 self.assertEqual('code_font', response.prefs[0].name)
321 self.assertEqual('true', response.prefs[0].value)
322
323 def testGetUserPrefs_Other_Allowed(self):
324 """A site admin can read another user's prefs."""
325 self.services.user.SetUserPrefs(
326 self.cnxn, 111,
327 [user_pb2.UserPrefValue(name='code_font', value='true')])
328 self.user_2.is_site_admin = True
329
330 request = users_pb2.GetUserPrefsRequest()
331 request.user_ref.display_name = 'owner@example.com'
332 mc = monorailcontext.MonorailContext(
333 self.services, cnxn=self.cnxn, requester='test2@example.com')
334 mc.LookupLoggedInUserPerms(self.project)
335 response = self.CallWrapped(self.users_svcr.GetUserPrefs, mc, request)
336
337 self.assertEqual(1, len(response.prefs))
338 self.assertEqual('code_font', response.prefs[0].name)
339 self.assertEqual('true', response.prefs[0].value)
340
341 def testGetUserPrefs_Other_Denied(self):
342 """A non-admin cannot read another user's prefs."""
343 self.services.user.SetUserPrefs(
344 self.cnxn, 111,
345 [user_pb2.UserPrefValue(name='code_font', value='true')])
346 # user2 is not a site admin.
347
348 request = users_pb2.GetUserPrefsRequest()
349 request.user_ref.display_name = 'owner@example.com'
350 mc = monorailcontext.MonorailContext(
351 self.services, cnxn=self.cnxn, requester='test2@example.com')
352 mc.LookupLoggedInUserPerms(self.project)
353 with self.assertRaises(permissions.PermissionException):
354 self.CallWrapped(self.users_svcr.GetUserPrefs, mc, request)
355
356 def testSetUserPrefs_Anon(self):
357 """Anon cannot set prefs."""
358 request = users_pb2.SetUserPrefsRequest()
359 mc = monorailcontext.MonorailContext(
360 self.services, cnxn=self.cnxn, requester=None)
361 with self.assertRaises(exceptions.InputException):
362 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
363
364 def testSetUserPrefs_Mine_Empty(self):
365 """Setting zero prefs is a no-op.."""
366 request = users_pb2.SetUserPrefsRequest()
367 mc = monorailcontext.MonorailContext(
368 self.services, cnxn=self.cnxn, requester='owner@example.com')
369 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
370
371 prefs_after = self.services.user.GetUserPrefs(self.cnxn, 111)
372 self.assertEqual(0, len(prefs_after.prefs))
373
374 def testSetUserPrefs_Mine_Add(self):
375 """User can set a preference for the first time."""
376 request = users_pb2.SetUserPrefsRequest(
377 prefs=[user_objects_pb2.UserPrefValue(name='code_font', value='true')])
378 mc = monorailcontext.MonorailContext(
379 self.services, cnxn=self.cnxn, requester='owner@example.com')
380 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
381
382 prefs_after = self.services.user.GetUserPrefs(self.cnxn, 111)
383 self.assertEqual(1, len(prefs_after.prefs))
384 self.assertEqual('code_font', prefs_after.prefs[0].name)
385 self.assertEqual('true', prefs_after.prefs[0].value)
386
387 def testSetUserPrefs_Mine_Overwrite(self):
388 """User can change the value of a pref."""
389 self.services.user.SetUserPrefs(
390 self.cnxn, 111,
391 [user_pb2.UserPrefValue(name='code_font', value='true')])
392 request = users_pb2.SetUserPrefsRequest(
393 prefs=[user_objects_pb2.UserPrefValue(name='code_font', value='false')])
394 mc = monorailcontext.MonorailContext(
395 self.services, cnxn=self.cnxn, requester='owner@example.com')
396 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
397
398 prefs_after = self.services.user.GetUserPrefs(self.cnxn, 111)
399 self.assertEqual(1, len(prefs_after.prefs))
400 self.assertEqual('code_font', prefs_after.prefs[0].name)
401 self.assertEqual('false', prefs_after.prefs[0].value)
402
403 def testSetUserPrefs_Other_Allowed(self):
404 """A site admin can update another user's prefs."""
405 self.services.user.SetUserPrefs(
406 self.cnxn, 111,
407 [user_pb2.UserPrefValue(name='code_font', value='true')])
408 self.user_2.is_site_admin = True
409
410 request = users_pb2.SetUserPrefsRequest(
411 prefs=[user_objects_pb2.UserPrefValue(name='code_font', value='false')])
412 request.user_ref.display_name = 'owner@example.com'
413 mc = monorailcontext.MonorailContext(
414 self.services, cnxn=self.cnxn, requester='test2@example.com')
415 mc.LookupLoggedInUserPerms(self.project)
416 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
417
418 prefs_after = self.services.user.GetUserPrefs(self.cnxn, 111)
419 self.assertEqual(1, len(prefs_after.prefs))
420 self.assertEqual('code_font', prefs_after.prefs[0].name)
421 self.assertEqual('false', prefs_after.prefs[0].value)
422
423 def testSetUserPrefs_Other_Denied(self):
424 """A non-admin cannot set another user's prefs."""
425 self.services.user.SetUserPrefs(
426 self.cnxn, 111,
427 [user_pb2.UserPrefValue(name='code_font', value='true')])
428 # user2 is not a site admin.
429
430 request = users_pb2.SetUserPrefsRequest(
431 prefs=[user_objects_pb2.UserPrefValue(name='code_font', value='false')])
432 request.user_ref.display_name = 'owner@example.com'
433 mc = monorailcontext.MonorailContext(
434 self.services, cnxn=self.cnxn, requester='test2@example.com')
435 mc.LookupLoggedInUserPerms(self.project)
436 with self.assertRaises(permissions.PermissionException):
437 self.CallWrapped(self.users_svcr.SetUserPrefs, mc, request)
438
439 # Regardless of any exception, the preferences remain unchanged.
440 prefs_after = self.services.user.GetUserPrefs(self.cnxn, 111)
441 self.assertEqual(1, len(prefs_after.prefs))
442 self.assertEqual('code_font', prefs_after.prefs[0].name)
443 self.assertEqual('true', prefs_after.prefs[0].value)
444
445 def testInviteLinkedParent_NotFound(self):
446 """Reject attempt to invite a user that does not exist."""
447 self.services.user.TestAddUser('user@google.com', 333)
448 request = users_pb2.InviteLinkedParentRequest(
449 email='who@chromium.org') # Does not exist.
450 mc = monorailcontext.MonorailContext(
451 self.services, cnxn=self.cnxn, requester='who@google.com')
452 with self.assertRaises(exceptions.NoSuchUserException):
453 self.CallWrapped(self.users_svcr.InviteLinkedParent, mc, request)
454
455 def testInviteLinkedParent_Normal(self):
456 """We can invite accounts to link when all criteria are met."""
457 self.services.user.TestAddUser('user@google.com', 333)
458 self.services.user.TestAddUser('user@chromium.org', 444)
459 request = users_pb2.InviteLinkedParentRequest(
460 email='user@google.com')
461 mc = monorailcontext.MonorailContext(
462 self.services, cnxn=self.cnxn, requester='user@chromium.org')
463 self.CallWrapped(self.users_svcr.InviteLinkedParent, mc, request)
464
465 (invite_as_parent, invite_as_child
466 ) = self.services.user.GetPendingLinkedInvites(self.cnxn, 333)
467 self.assertEqual([444], invite_as_parent)
468 self.assertEqual([], invite_as_child)
469 (invite_as_parent, invite_as_child
470 ) = self.services.user.GetPendingLinkedInvites(self.cnxn, 444)
471 self.assertEqual([], invite_as_parent)
472 self.assertEqual([333], invite_as_child)
473
474 def testAcceptLinkedChild_NotFound(self):
475 """Reject attempt to link a user that does not exist."""
476 self.services.user.TestAddUser('user@google.com', 333)
477 request = users_pb2.AcceptLinkedChildRequest(
478 email='who@chromium.org') # Does not exist.
479 mc = monorailcontext.MonorailContext(
480 self.services, cnxn=self.cnxn, requester='who@google.com')
481 with self.assertRaises(exceptions.NoSuchUserException):
482 self.CallWrapped(self.users_svcr.AcceptLinkedChild, mc, request)
483
484 def testAcceptLinkedChild_NoInvite(self):
485 """Reject attempt to link accounts when there was no invite."""
486 self.services.user.TestAddUser('user@google.com', 333)
487 self.services.user.TestAddUser('user@chromium.org', 444)
488 request = users_pb2.AcceptLinkedChildRequest(
489 email='user@chromium.org')
490 mc = monorailcontext.MonorailContext(
491 self.services, cnxn=self.cnxn, requester='user@google.com')
492 with self.assertRaises(exceptions.InputException):
493 self.CallWrapped(self.users_svcr.AcceptLinkedChild, mc, request)
494
495 def testAcceptLinkedChild_Normal(self):
496 """We can linke accounts when all criteria are met."""
497 parent = self.services.user.TestAddUser('user@google.com', 333)
498 child = self.services.user.TestAddUser('user@chromium.org', 444)
499 self.services.user.InviteLinkedParent(
500 self.cnxn, parent.user_id, child.user_id)
501 request = users_pb2.AcceptLinkedChildRequest(
502 email='user@chromium.org')
503 mc = monorailcontext.MonorailContext(
504 self.services, cnxn=self.cnxn, requester='user@google.com')
505 self.CallWrapped(self.users_svcr.AcceptLinkedChild, mc, request)
506
507 self.assertEqual(parent.user_id, child.linked_parent_id)
508 self.assertIn(child.user_id, parent.linked_child_ids)
509
510 def testUnlinkAccounts_NotFound(self):
511 """Reject attempt to unlink a user that does not exist or unspecified."""
512 mc = monorailcontext.MonorailContext(
513 self.services, cnxn=self.cnxn, requester='owner@example.com')
514
515 request = users_pb2.UnlinkAccountsRequest(
516 parent=common_pb2.UserRef(display_name='who@chromium.org'),
517 child=common_pb2.UserRef(display_name='owner@example.com'))
518 with self.assertRaises(exceptions.NoSuchUserException):
519 self.CallWrapped(self.users_svcr.UnlinkAccounts, mc, request)
520
521 request = users_pb2.UnlinkAccountsRequest(
522 parent=common_pb2.UserRef(display_name='owner@example.com'),
523 child=common_pb2.UserRef(display_name='who@google.com'))
524 with self.assertRaises(exceptions.NoSuchUserException):
525 self.CallWrapped(self.users_svcr.UnlinkAccounts, mc, request)
526
527 request = users_pb2.UnlinkAccountsRequest(
528 parent=common_pb2.UserRef(display_name='owner@example.com'))
529 with self.assertRaises(exceptions.InputException):
530 self.CallWrapped(self.users_svcr.UnlinkAccounts, mc, request)
531
532 request = users_pb2.UnlinkAccountsRequest(
533 child=common_pb2.UserRef(display_name='owner@example.com'))
534 with self.assertRaises(exceptions.InputException):
535 self.CallWrapped(self.users_svcr.UnlinkAccounts, mc, request)
536
537 def testUnlinkAccounts_Normal(self):
538 """Users can unlink their accounts."""
539 self.services.user.linked_account_rows = [(111, 222)]
540 request = users_pb2.UnlinkAccountsRequest(
541 parent=common_pb2.UserRef(display_name='owner@example.com'),
542 child=common_pb2.UserRef(display_name='test2@example.com'))
543 mc = monorailcontext.MonorailContext(
544 self.services, cnxn=self.cnxn, requester='owner@example.com')
545
546 self.CallWrapped(self.users_svcr.UnlinkAccounts, mc, request)
547
548 self.assertEqual([], self.services.user.linked_account_rows)
549
550 def AddUserProjects(self, user_id):
551 project_states = {
552 'live': project_pb2.ProjectState.LIVE,
553 'archived': project_pb2.ProjectState.ARCHIVED,
554 'deletable': project_pb2.ProjectState.DELETABLE}
555
556 for name, state in project_states.items():
557 self.services.project.TestAddProject(
558 'owner-%s-%s' % (name, user_id), state=state, owner_ids=[user_id])
559 self.services.project.TestAddProject(
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100560 'committer-%s-%s' % (name, user_id),
561 state=state,
Copybara854996b2021-09-07 19:36:02 +0000562 committer_ids=[user_id])
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100563 self.services.project.TestAddProject(
564 'contributor-%s-%s' % (name, user_id),
565 state=state,
566 contrib_ids=[user_id])
Copybara854996b2021-09-07 19:36:02 +0000567
568 members_only = self.services.project.TestAddProject(
569 'members-only-' + str(user_id), owner_ids=[user_id])
570 members_only.access = project_pb2.ProjectAccess.MEMBERS_ONLY
571
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100572 @pytest.mark.skip(reason='Test is flaky (https://crbug.com/monorail/12052)')
Copybara854996b2021-09-07 19:36:02 +0000573 def testGetUsersProjects(self):
574 self.user = self.services.user.TestAddUser('test3@example.com', 333)
575 self.services.project_star.SetStar(
576 self.cnxn, self.project.project_id, 222, True)
577 self.project.committer_ids.extend([222])
578
579 self.AddUserProjects(222)
580 self.AddUserProjects(333)
581
582 request = users_pb2.GetUsersProjectsRequest(user_refs=[
583 common_pb2.UserRef(display_name='test2@example.com'),
584 common_pb2.UserRef(display_name='test3@example.com')])
585 mc = monorailcontext.MonorailContext(
586 self.services, cnxn=self.cnxn, requester='test2@example.com')
587 mc.LookupLoggedInUserPerms(self.project)
588 response = self.CallWrapped(
589 self.users_svcr.GetUsersProjects, mc, request)
590
591 self.assertEqual([
592 user_objects_pb2.UserProjects(
593 user_ref=common_pb2.UserRef(display_name='test2@example.com'),
594 owner_of=['members-only-222', 'owner-live-222'],
595 member_of=['committer-live-222', 'proj'],
596 contributor_to=['contributor-live-222'],
597 starred_projects=['proj']),
598 user_objects_pb2.UserProjects(
599 user_ref=common_pb2.UserRef(display_name='test3@example.com'),
600 owner_of=['owner-live-333'],
601 member_of=['committer-live-333'],
602 contributor_to=['contributor-live-333'])],
603 list(response.users_projects))
604
605 def testGetUsersProjects_NoUserRefs(self):
606 request = users_pb2.GetUsersProjectsRequest()
607 mc = monorailcontext.MonorailContext(
608 self.services, cnxn=self.cnxn, requester='test2@example.com')
609 mc.LookupLoggedInUserPerms(self.project)
610 response = self.CallWrapped(
611 self.users_svcr.GetUsersProjects, mc, request)
612 self.assertEqual([], list(response.users_projects))