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