blob: 5ea05a6d92db2f1317702fb21bcc695c776223bb [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2016 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 monorail.framework.framework_bizobj."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import unittest
11import mock
12
13import settings
14from framework import authdata
15from framework import framework_bizobj
16from framework import framework_constants
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010017from mrproto import project_pb2
18from mrproto import tracker_pb2
19from mrproto import user_pb2
Copybara854996b2021-09-07 19:36:02 +000020from services import service_manager
21from services import client_config_svc
22from testing import fake
23from testing import testing_helpers
24from tracker import tracker_bizobj
25
26
27class CreateUserDisplayNamesAndEmailsTest(unittest.TestCase):
28
29 def setUp(self):
30 self.cnxn = fake.MonorailConnection()
31 self.services = service_manager.Services(
32 project=fake.ProjectService(),
33 user=fake.UserService(),
34 usergroup=fake.UserGroupService())
35
36 self.user_1 = self.services.user.TestAddUser(
37 'user_1@test.com', 111, obscure_email=True)
38 self.user_2 = self.services.user.TestAddUser(
39 'user_2@test.com', 222, obscure_email=False)
40 self.user_3 = self.services.user.TestAddUser(
41 'user_3@test.com', 333, obscure_email=True)
42 self.user_4 = self.services.user.TestAddUser(
43 'user_4@test.com', 444, obscure_email=False)
44 self.service_account = self.services.user.TestAddUser(
45 'service@account.com', 999, obscure_email=True)
46 self.user_deleted = self.services.user.TestAddUser(
47 '', framework_constants.DELETED_USER_ID)
48 self.requester = self.services.user.TestAddUser('user_5@test.com', 555)
49 self.user_auth = authdata.AuthData(
50 user_id=self.requester.user_id, email=self.requester.email)
51 self.project = self.services.project.TestAddProject(
52 'proj',
53 project_id=789,
54 owner_ids=[self.user_1.user_id],
55 committer_ids=[self.user_2.user_id, self.service_account.user_id])
56
57 @mock.patch('services.client_config_svc.GetServiceAccountMap')
58 def testUserCreateDisplayNamesAndEmails_NonProjectMembers(
59 self, fake_account_map):
60 fake_account_map.return_value = {'service@account.com': 'Service'}
61 users = [self.user_1, self.user_2, self.user_3, self.user_4,
62 self.service_account, self.user_deleted]
63 (display_names_by_id,
64 display_emails_by_id) = framework_bizobj.CreateUserDisplayNamesAndEmails(
65 self.cnxn, self.services, self.user_auth, users)
66 expected_display_names = {
67 self.user_1.user_id: testing_helpers.ObscuredEmail(self.user_1.email),
68 self.user_2.user_id: self.user_2.email,
69 self.user_3.user_id: testing_helpers.ObscuredEmail(self.user_3.email),
70 self.user_4.user_id: self.user_4.email,
71 self.service_account.user_id: 'Service',
72 self.user_deleted.user_id: framework_constants.DELETED_USER_NAME}
73 expected_display_emails = {
74 self.user_1.user_id:
75 testing_helpers.ObscuredEmail(self.user_1.email),
76 self.user_2.user_id:
77 self.user_2.email,
78 self.user_3.user_id:
79 testing_helpers.ObscuredEmail(self.user_3.email),
80 self.user_4.user_id:
81 self.user_4.email,
82 self.service_account.user_id:
83 testing_helpers.ObscuredEmail(self.service_account.email),
84 self.user_deleted.user_id: '',
85 }
86 self.assertEqual(display_names_by_id, expected_display_names)
87 self.assertEqual(display_emails_by_id, expected_display_emails)
88
89 @mock.patch('services.client_config_svc.GetServiceAccountMap')
90 def testUserCreateDisplayNamesAndEmails_ProjectMember(self, fake_account_map):
91 fake_account_map.return_value = {'service@account.com': 'Service'}
92 users = [self.user_1, self.user_2, self.user_3, self.user_4,
93 self.service_account, self.user_deleted]
94 self.project.committer_ids.append(self.requester.user_id)
95 (display_names_by_id,
96 display_emails_by_id) = framework_bizobj.CreateUserDisplayNamesAndEmails(
97 self.cnxn, self.services, self.user_auth, users)
98 expected_display_names = {
99 self.user_1.user_id: self.user_1.email, # Project member
100 self.user_2.user_id: self.user_2.email, # Project member and unobscured
101 self.user_3.user_id: testing_helpers.ObscuredEmail(self.user_3.email),
102 self.user_4.user_id: self.user_4.email, # Unobscured email
103 self.service_account.user_id: 'Service',
104 self.user_deleted.user_id: framework_constants.DELETED_USER_NAME
105 }
106 expected_display_emails = {
107 self.user_1.user_id: self.user_1.email, # Project member
108 self.user_2.user_id: self.user_2.email, # Project member and unobscured
109 self.user_3.user_id: testing_helpers.ObscuredEmail(self.user_3.email),
110 self.user_4.user_id: self.user_4.email, # Unobscured email
111 self.service_account.user_id: self.service_account.email,
112 self.user_deleted.user_id: ''
113 }
114 self.assertEqual(display_names_by_id, expected_display_names)
115 self.assertEqual(display_emails_by_id, expected_display_emails)
116
117 @mock.patch('services.client_config_svc.GetServiceAccountMap')
118 def testUserCreateDisplayNamesAndEmails_Admin(self, fake_account_map):
119 fake_account_map.return_value = {'service@account.com': 'Service'}
120 users = [self.user_1, self.user_2, self.user_3, self.user_4,
121 self.service_account, self.user_deleted]
122 self.user_auth.user_pb.is_site_admin = True
123 (display_names_by_id,
124 display_emails_by_id) = framework_bizobj.CreateUserDisplayNamesAndEmails(
125 self.cnxn, self.services, self.user_auth, users)
126 expected_display_names = {
127 self.user_1.user_id: self.user_1.email,
128 self.user_2.user_id: self.user_2.email,
129 self.user_3.user_id: self.user_3.email,
130 self.user_4.user_id: self.user_4.email,
131 self.service_account.user_id: 'Service',
132 self.user_deleted.user_id: framework_constants.DELETED_USER_NAME}
133 expected_display_emails = {
134 self.user_1.user_id: self.user_1.email,
135 self.user_2.user_id: self.user_2.email,
136 self.user_3.user_id: self.user_3.email,
137 self.user_4.user_id: self.user_4.email,
138 self.service_account.user_id: self.service_account.email,
139 self.user_deleted.user_id: ''
140 }
141
142 self.assertEqual(display_names_by_id, expected_display_names)
143 self.assertEqual(display_emails_by_id, expected_display_emails)
144
145
146class ParseAndObscureAddressTest(unittest.TestCase):
147
148 def testParseAndObscureAddress(self):
149 email = 'sir.chicken@farm.test'
150 (username, user_domain, obscured_username,
151 obscured_email) = framework_bizobj.ParseAndObscureAddress(email)
152
153 self.assertEqual(username, 'sir.chicken')
154 self.assertEqual(user_domain, 'farm.test')
155 self.assertEqual(obscured_username, 'sir.c')
156 self.assertEqual(obscured_email, 'sir.c...@farm.test')
157
158
159class FilterViewableEmailsTest(unittest.TestCase):
160
161 def setUp(self):
162 self.cnxn = fake.MonorailConnection()
163 self.services = service_manager.Services(
164 project=fake.ProjectService(),
165 user=fake.UserService(),
166 usergroup=fake.UserGroupService())
167 self.user_1 = self.services.user.TestAddUser(
168 'user_1@test.com', 111, obscure_email=True)
169 self.user_2 = self.services.user.TestAddUser(
170 'user_2@test.com', 222, obscure_email=False)
171 self.requester = self.services.user.TestAddUser(
172 'user_5@test.com', 555, obscure_email=True)
173 self.user_auth = authdata.AuthData(
174 user_id=self.requester.user_id, email=self.requester.email)
175 self.user_auth.user_pb.email = self.user_auth.email
176 self.project = self.services.project.TestAddProject(
177 'proj', project_id=789, owner_ids=[111], committer_ids=[222])
178
179 def testFilterViewableEmail_Anon(self):
180 anon = authdata.AuthData()
181 other_users = [self.user_1, self.user_2]
182 filtered_users = framework_bizobj.FilterViewableEmails(
183 self.cnxn, self.services, anon, other_users)
184 self.assertEqual(filtered_users, [])
185
186 def testFilterViewableEmail_Self(self):
187 filtered_users = framework_bizobj.FilterViewableEmails(
188 self.cnxn, self.services, self.user_auth, [self.user_auth.user_pb])
189 self.assertEqual(filtered_users, [self.user_auth.user_pb])
190
191 def testFilterViewableEmail_SiteAdmin(self):
192 self.user_auth.user_pb.is_site_admin = True
193 other_users = [self.user_1, self.user_2]
194 filtered_users = framework_bizobj.FilterViewableEmails(
195 self.cnxn, self.services, self.user_auth, other_users)
196 self.assertEqual(filtered_users, other_users)
197
198 def testFilterViewableEmail_InDisplayNameGroup(self):
199 display_name_group_id = 666
200 self.services.usergroup.TestAddGroupSettings(
201 display_name_group_id, 'display-perm-perm@email.com')
202 settings.full_emails_perm_groups = ['display-perm-perm@email.com']
203 self.user_auth.effective_ids.add(display_name_group_id)
204
205 other_users = [self.user_1, self.user_2]
206 filtered_users = framework_bizobj.FilterViewableEmails(
207 self.cnxn, self.services, self.user_auth, other_users)
208 self.assertEqual(filtered_users, other_users)
209
210 def testFilterViewableEmail_NonMember(self):
211 other_users = [self.user_1, self.user_2]
212 filtered_users = framework_bizobj.FilterViewableEmails(
213 self.cnxn, self.services, self.user_auth, other_users)
214 self.assertEqual(filtered_users, [])
215
216 def testFilterViewableEmail_ProjectMember(self):
217 self.project.committer_ids.append(self.requester.user_id)
218 other_users = [self.user_1, self.user_2]
219 filtered_users = framework_bizobj.FilterViewableEmails(
220 self.cnxn, self.services, self.user_auth, other_users)
221 self.assertEqual(filtered_users, other_users)
222
223
224# TODO(https://crbug.com/monorail/8192): Remove deprecated tests.
225class DeprecatedShouldRevealEmailTest(unittest.TestCase):
226
227 def setUp(self):
228 self.cnxn = fake.MonorailConnection()
229 self.services = service_manager.Services(
230 project=fake.ProjectService(),
231 user=fake.UserService(),
232 usergroup=fake.UserGroupService())
233 self.user_1 = self.services.user.TestAddUser(
234 'user_1@test.com', 111, obscure_email=True)
235 self.user_2 = self.services.user.TestAddUser(
236 'user_2@test.com', 222, obscure_email=False)
237 self.requester = self.services.user.TestAddUser(
238 'user_5@test.com', 555, obscure_email=True)
239 self.user_auth = authdata.AuthData(
240 user_id=self.requester.user_id, email=self.requester.email)
241 self.user_auth.user_pb.email = self.user_auth.email
242 self.project = self.services.project.TestAddProject(
243 'proj', project_id=789, owner_ids=[111], committer_ids=[222])
244
245 def testDeprecatedShouldRevealEmail_Anon(self):
246 anon = authdata.AuthData()
247 self.assertFalse(
248 framework_bizobj.DeprecatedShouldRevealEmail(
249 anon, self.project, self.user_1.email))
250 self.assertFalse(
251 framework_bizobj.DeprecatedShouldRevealEmail(
252 anon, self.project, self.user_2.email))
253
254 def testDeprecatedShouldRevealEmail_Self(self):
255 self.assertTrue(
256 framework_bizobj.DeprecatedShouldRevealEmail(
257 self.user_auth, self.project, self.user_auth.user_pb.email))
258
259 def testDeprecatedShouldRevealEmail_SiteAdmin(self):
260 self.user_auth.user_pb.is_site_admin = True
261 self.assertTrue(
262 framework_bizobj.DeprecatedShouldRevealEmail(
263 self.user_auth, self.project, self.user_1.email))
264 self.assertTrue(
265 framework_bizobj.DeprecatedShouldRevealEmail(
266 self.user_auth, self.project, self.user_2.email))
267
268 def testDeprecatedShouldRevealEmail_ProjectMember(self):
269 self.project.committer_ids.append(self.requester.user_id)
270 self.assertTrue(
271 framework_bizobj.DeprecatedShouldRevealEmail(
272 self.user_auth, self.project, self.user_1.email))
273 self.assertTrue(
274 framework_bizobj.DeprecatedShouldRevealEmail(
275 self.user_auth, self.project, self.user_2.email))
276
277 def testDeprecatedShouldRevealEmail_NonMember(self):
278 self.assertFalse(
279 framework_bizobj.DeprecatedShouldRevealEmail(
280 self.user_auth, self.project, self.user_1.email))
281 self.assertFalse(
282 framework_bizobj.DeprecatedShouldRevealEmail(
283 self.user_auth, self.project, self.user_2.email))
284
285
286class ArtifactTest(unittest.TestCase):
287
288 def setUp(self):
289 # No custom fields. Exclusive prefixes: Type, Priority, Milestone.
290 self.config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
291
292 def testMergeLabels_Labels(self):
293 # Empty case.
294 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
295 [], [], [], self.config)
296 self.assertEqual(merged_labels, [])
297 self.assertEqual(update_add, [])
298 self.assertEqual(update_remove, [])
299
300 # No-op case.
301 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
302 ['a', 'b'], [], [], self.config)
303 self.assertEqual(merged_labels, ['a', 'b'])
304 self.assertEqual(update_add, [])
305 self.assertEqual(update_remove, [])
306
307 # Adding and removing at the same time.
308 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
309 ['a', 'b', 'd'], ['c'], ['d'], self.config)
310 self.assertEqual(merged_labels, ['a', 'b', 'c'])
311 self.assertEqual(update_add, ['c'])
312 self.assertEqual(update_remove, ['d'])
313
314 # Removing a non-matching label has no effect.
315 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
316 ['a', 'b', 'd'], ['d'], ['e'], self.config)
317 self.assertEqual(merged_labels, ['a', 'b', 'd'])
318 self.assertEqual(update_add, []) # d was already there.
319 self.assertEqual(update_remove, []) # there was no e.
320
321 # We can add and remove at the same time.
322 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
323 ['Priority-Medium', 'OpSys-OSX'], ['Hot'], ['OpSys-OSX'], self.config)
324 self.assertEqual(merged_labels, ['Priority-Medium', 'Hot'])
325 self.assertEqual(update_add, ['Hot'])
326 self.assertEqual(update_remove, ['OpSys-OSX'])
327
328 # Adding Priority-High replaces Priority-Medium.
329 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
330 ['Priority-Medium', 'OpSys-OSX'], ['Priority-High', 'OpSys-Win'], [],
331 self.config)
332 self.assertEqual(merged_labels, ['OpSys-OSX', 'Priority-High', 'OpSys-Win'])
333 self.assertEqual(update_add, ['Priority-High', 'OpSys-Win'])
334 self.assertEqual(update_remove, [])
335
336 # Adding Priority-High and Priority-Low replaces with High only.
337 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
338 ['Priority-Medium', 'OpSys-OSX'],
339 ['Priority-High', 'Priority-Low'], [], self.config)
340 self.assertEqual(merged_labels, ['OpSys-OSX', 'Priority-High'])
341 self.assertEqual(update_add, ['Priority-High'])
342 self.assertEqual(update_remove, [])
343
344 # Removing a mix of matching and non-matching labels only does matching.
345 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
346 ['Priority-Medium', 'OpSys-OSX'], [], ['Priority-Medium', 'OpSys-Win'],
347 self.config)
348 self.assertEqual(merged_labels, ['OpSys-OSX'])
349 self.assertEqual(update_add, [])
350 self.assertEqual(update_remove, ['Priority-Medium'])
351
352 # Multi-part labels work as expected.
353 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
354 ['Priority-Medium', 'OpSys-OSX-11'],
355 ['Priority-Medium-Rare', 'OpSys-OSX-13'], [], self.config)
356 self.assertEqual(
357 merged_labels, ['OpSys-OSX-11', 'Priority-Medium-Rare', 'OpSys-OSX-13'])
358 self.assertEqual(update_add, ['Priority-Medium-Rare', 'OpSys-OSX-13'])
359 self.assertEqual(update_remove, [])
360
361 # Multi-part exclusive prefixes only filter labels that match whole prefix.
362 self.config.exclusive_label_prefixes.append('Branch-Name')
363 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
364 ['Branch-Name-xyz'],
365 ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
366 self.assertEqual(merged_labels, ['Branch-Prediction', 'Branch-Name-Beta'])
367 self.assertEqual(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
368 self.assertEqual(update_remove, [])
369
370 def testMergeLabels_SingleValuedEnums(self):
371 self.config.field_defs.append(tracker_pb2.FieldDef(
372 field_id=1, field_name='Size',
373 field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
374 is_multivalued=False))
375 self.config.field_defs.append(tracker_pb2.FieldDef(
376 field_id=1, field_name='Branch-Name',
377 field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
378 is_multivalued=False))
379
380 # We can add a label for a single-valued enum.
381 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
382 ['Priority-Medium', 'OpSys-OSX'], ['Size-L'], [], self.config)
383 self.assertEqual(merged_labels, ['Priority-Medium', 'OpSys-OSX', 'Size-L'])
384 self.assertEqual(update_add, ['Size-L'])
385 self.assertEqual(update_remove, [])
386
387 # Adding and removing the same label adds it.
388 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
389 ['Priority-Medium'], ['Size-M'], ['Size-M'], self.config)
390 self.assertEqual(merged_labels, ['Priority-Medium', 'Size-M'])
391 self.assertEqual(update_add, ['Size-M'])
392 self.assertEqual(update_remove, [])
393
394 # Adding Size-L replaces Size-M.
395 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
396 ['Priority-Medium', 'Size-M'], ['Size-L', 'OpSys-Win'], [],
397 self.config)
398 self.assertEqual(merged_labels, ['Priority-Medium', 'Size-L', 'OpSys-Win'])
399 self.assertEqual(update_add, ['Size-L', 'OpSys-Win'])
400 self.assertEqual(update_remove, [])
401
402 # Adding Size-L and Size-XL replaces with L only.
403 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
404 ['Size-M', 'OpSys-OSX'], ['Size-L', 'Size-XL'], [], self.config)
405 self.assertEqual(merged_labels, ['OpSys-OSX', 'Size-L'])
406 self.assertEqual(update_add, ['Size-L'])
407 self.assertEqual(update_remove, [])
408
409 # Multi-part labels work as expected.
410 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
411 ['Size-M', 'OpSys-OSX'], ['Size-M-USA'], [], self.config)
412 self.assertEqual(merged_labels, ['OpSys-OSX', 'Size-M-USA'])
413 self.assertEqual(update_add, ['Size-M-USA'])
414 self.assertEqual(update_remove, [])
415
416 # Multi-part enum names only filter labels that match whole name.
417 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
418 ['Branch-Name-xyz'],
419 ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
420 self.assertEqual(merged_labels, ['Branch-Prediction', 'Branch-Name-Beta'])
421 self.assertEqual(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
422 self.assertEqual(update_remove, [])
423
424 def testMergeLabels_MultiValuedEnums(self):
425 self.config.field_defs.append(tracker_pb2.FieldDef(
426 field_id=1, field_name='OpSys',
427 field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
428 is_multivalued=True))
429 self.config.field_defs.append(tracker_pb2.FieldDef(
430 field_id=1, field_name='Branch-Name',
431 field_type=tracker_pb2.FieldTypes.ENUM_TYPE,
432 is_multivalued=True))
433
434 # We can add a label for a multi-valued enum.
435 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
436 ['Priority-Medium'], ['OpSys-Win'], [], self.config)
437 self.assertEqual(merged_labels, ['Priority-Medium', 'OpSys-Win'])
438 self.assertEqual(update_add, ['OpSys-Win'])
439 self.assertEqual(update_remove, [])
440
441 # We can remove a matching label for a multi-valued enum.
442 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
443 ['Priority-Medium', 'OpSys-Win'], [], ['OpSys-Win'], self.config)
444 self.assertEqual(merged_labels, ['Priority-Medium'])
445 self.assertEqual(update_add, [])
446 self.assertEqual(update_remove, ['OpSys-Win'])
447
448 # We can remove a non-matching label and it is a no-op.
449 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
450 ['Priority-Medium', 'OpSys-OSX'], [], ['OpSys-Win'], self.config)
451 self.assertEqual(merged_labels, ['Priority-Medium', 'OpSys-OSX'])
452 self.assertEqual(update_add, [])
453 self.assertEqual(update_remove, [])
454
455 # Adding and removing the same label adds it.
456 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
457 ['Priority-Medium'], ['OpSys-Win'], ['OpSys-Win'], self.config)
458 self.assertEqual(merged_labels, ['Priority-Medium', 'OpSys-Win'])
459 self.assertEqual(update_add, ['OpSys-Win'])
460 self.assertEqual(update_remove, [])
461
462 # We can add a label for a multi-valued enum, even if matching exists.
463 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
464 ['Priority-Medium', 'OpSys-OSX'], ['OpSys-Win'], [], self.config)
465 self.assertEqual(
466 merged_labels, ['Priority-Medium', 'OpSys-OSX', 'OpSys-Win'])
467 self.assertEqual(update_add, ['OpSys-Win'])
468 self.assertEqual(update_remove, [])
469
470 # Adding two at the same time is fine.
471 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
472 ['Size-M', 'OpSys-OSX'], ['OpSys-Win', 'OpSys-Vax'], [], self.config)
473 self.assertEqual(
474 merged_labels, ['Size-M', 'OpSys-OSX', 'OpSys-Win', 'OpSys-Vax'])
475 self.assertEqual(update_add, ['OpSys-Win', 'OpSys-Vax'])
476 self.assertEqual(update_remove, [])
477
478 # Multi-part labels work as expected.
479 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
480 ['Size-M', 'OpSys-OSX'], ['OpSys-Win-10'], [], self.config)
481 self.assertEqual(merged_labels, ['Size-M', 'OpSys-OSX', 'OpSys-Win-10'])
482 self.assertEqual(update_add, ['OpSys-Win-10'])
483 self.assertEqual(update_remove, [])
484
485 # Multi-part enum names don't mess up anything.
486 (merged_labels, update_add, update_remove) = framework_bizobj.MergeLabels(
487 ['Branch-Name-xyz'],
488 ['Branch-Prediction', 'Branch-Name-Beta'], [], self.config)
489 self.assertEqual(
490 merged_labels,
491 ['Branch-Name-xyz', 'Branch-Prediction', 'Branch-Name-Beta'])
492 self.assertEqual(update_add, ['Branch-Prediction', 'Branch-Name-Beta'])
493 self.assertEqual(update_remove, [])
494
495
496class CanonicalizeLabelTest(unittest.TestCase):
497
498 def testCanonicalizeLabel(self):
499 self.assertEqual(None, framework_bizobj.CanonicalizeLabel(None))
500 self.assertEqual('FooBar', framework_bizobj.CanonicalizeLabel('Foo Bar '))
501 self.assertEqual('Foo.Bar',
502 framework_bizobj.CanonicalizeLabel('Foo . Bar '))
503 self.assertEqual('Foo-Bar',
504 framework_bizobj.CanonicalizeLabel('Foo - Bar '))
505
506
507class UserIsInProjectTest(unittest.TestCase):
508
509 def testUserIsInProject(self):
510 p = project_pb2.Project()
511 self.assertFalse(framework_bizobj.UserIsInProject(p, {10}))
512 self.assertFalse(framework_bizobj.UserIsInProject(p, set()))
513
514 p.owner_ids.extend([1, 2, 3])
515 p.committer_ids.extend([4, 5, 6])
516 p.contributor_ids.extend([7, 8, 9])
517 self.assertTrue(framework_bizobj.UserIsInProject(p, {1}))
518 self.assertTrue(framework_bizobj.UserIsInProject(p, {4}))
519 self.assertTrue(framework_bizobj.UserIsInProject(p, {7}))
520 self.assertFalse(framework_bizobj.UserIsInProject(p, {10}))
521
522 # Membership via group membership
523 self.assertTrue(framework_bizobj.UserIsInProject(p, {10, 4}))
524
525 # Membership via several group memberships
526 self.assertTrue(framework_bizobj.UserIsInProject(p, {1, 4}))
527
528 # Several irrelevant group memberships
529 self.assertFalse(framework_bizobj.UserIsInProject(p, {10, 11, 12}))
530
531
532class IsValidColumnSpecTest(unittest.TestCase):
533
534 def testIsValidColumnSpec(self):
535 self.assertTrue(
536 framework_bizobj.IsValidColumnSpec('some columns hey-honk hay.honk'))
537
538 self.assertTrue(framework_bizobj.IsValidColumnSpec('some'))
539
540 self.assertTrue(framework_bizobj.IsValidColumnSpec(''))
541
542 def testIsValidColumnSpec_NotValid(self):
543 self.assertFalse(
544 framework_bizobj.IsValidColumnSpec('some columns hey-honk hay.'))
545
546 self.assertFalse(framework_bizobj.IsValidColumnSpec('some columns hey-'))
547
548 self.assertFalse(framework_bizobj.IsValidColumnSpec('-some columns hey'))
549
550 self.assertFalse(framework_bizobj.IsValidColumnSpec('some .columns hey'))
551
552
553class ValidatePrefTest(unittest.TestCase):
554
555 def testUnknown(self):
556 msg = framework_bizobj.ValidatePref('shoe_size', 'true')
557 self.assertIn('shoe_size', msg)
558 self.assertIn('Unknown', msg)
559
560 msg = framework_bizobj.ValidatePref('', 'true')
561 self.assertIn('Unknown', msg)
562
563 def testTooLong(self):
564 msg = framework_bizobj.ValidatePref('code_font', 'x' * 100)
565 self.assertIn('code_font', msg)
566 self.assertIn('too long', msg)
567
568 def testKnownValid(self):
569 self.assertIsNone(framework_bizobj.ValidatePref('code_font', 'true'))
570 self.assertIsNone(framework_bizobj.ValidatePref('code_font', 'false'))
571
572 def testKnownInvalid(self):
573 msg = framework_bizobj.ValidatePref('code_font', '')
574 self.assertIn('Invalid', msg)
575
576 msg = framework_bizobj.ValidatePref('code_font', 'sometimes')
577 self.assertIn('Invalid', msg)
578
579
580class IsRestrictNewIssuesUserTest(unittest.TestCase):
581
582 def setUp(self):
583 self.cnxn = fake.MonorailConnection()
584 self.services = service_manager.Services(
585 user=fake.UserService(),
586 usergroup=fake.UserGroupService())
587 self.services.user.TestAddUser('corp_user@example.com', 111)
588 self.services.user.TestAddUser('corp_group@example.com', 888)
589 self.services.usergroup.TestAddGroupSettings(888, 'corp_group@example.com')
590
591 @mock.patch(
592 'settings.restrict_new_issues_user_groups', ['corp_group@example.com'])
593 def testNonRestrictNewIssuesUser(self):
594 """We detect when a user is not part of a corp user group."""
595 self.assertFalse(
596 framework_bizobj.IsRestrictNewIssuesUser(self.cnxn, self.services, 111))
597
598 @mock.patch(
599 'settings.restrict_new_issues_user_groups', ['corp_group@example.com'])
600 def testRestrictNewIssuesUser(self):
601 """We detect when a user is a member of such a group."""
602 self.services.usergroup.TestAddMembers(888, [111, 222])
603 self.assertTrue(
604 framework_bizobj.IsRestrictNewIssuesUser(self.cnxn, self.services, 111))
605
606
607class IsPublicIssueNoticeUserTest(unittest.TestCase):
608
609 def setUp(self):
610 self.cnxn = fake.MonorailConnection()
611 self.services = service_manager.Services(
612 user=fake.UserService(), usergroup=fake.UserGroupService())
613 self.services.user.TestAddUser('corp_user@example.com', 111)
614 self.services.user.TestAddUser('corp_group@example.com', 888)
615 self.services.usergroup.TestAddGroupSettings(888, 'corp_group@example.com')
616
617 @mock.patch(
618 'settings.public_issue_notice_user_groups', ['corp_group@example.com'])
619 def testNonPublicIssueNoticeUser(self):
620 """We detect when a user is not part of a corp user group."""
621 self.assertFalse(
622 framework_bizobj.IsPublicIssueNoticeUser(self.cnxn, self.services, 111))
623
624 @mock.patch(
625 'settings.public_issue_notice_user_groups', ['corp_group@example.com'])
626 def testPublicIssueNoticeUser(self):
627 """We detect when a user is a member of such a group."""
628 self.services.usergroup.TestAddMembers(888, [111, 222])
629 self.assertTrue(
630 framework_bizobj.IsPublicIssueNoticeUser(self.cnxn, self.services, 111))
631
632
633class GetEffectiveIdsTest(unittest.TestCase):
634
635 def setUp(self):
636 self.cnxn = fake.MonorailConnection()
637 self.services = service_manager.Services(
638 user=fake.UserService(), usergroup=fake.UserGroupService())
639 self.services.user.TestAddUser('test@example.com', 111)
640
641 def testNoMemberships(self):
642 """No user groups means effective_ids == {user_id}."""
643 effective_ids = framework_bizobj.GetEffectiveIds(
644 self.cnxn, self.services, [111])
645 self.assertEqual(effective_ids, {111: {111}})
646
647 def testNormalMemberships(self):
648 """effective_ids should be {user_id, group_id...}."""
649 self.services.usergroup.TestAddMembers(888, [111])
650 self.services.usergroup.TestAddMembers(999, [111])
651 effective_ids = framework_bizobj.GetEffectiveIds(
652 self.cnxn, self.services, [111])
653 self.assertEqual(effective_ids, {111: {111, 888, 999}})
654
655 def testComputedUserGroup(self):
656 """effective_ids should be {user_id, group_id...}."""
657 self.services.usergroup.TestAddGroupSettings(888, 'everyone@example.com')
658 effective_ids = framework_bizobj.GetEffectiveIds(
659 self.cnxn, self.services, [111])
660 self.assertEqual(effective_ids, {111: {111, 888}})
661
662 def testAccountHasParent(self):
663 """The parent's effective_ids are added to child's."""
664 child = self.services.user.TestAddUser('child@example.com', 111)
665 child.linked_parent_id = 222
666 parent = self.services.user.TestAddUser('parent@example.com', 222)
667 parent.linked_child_ids = [111]
668 effective_ids = framework_bizobj.GetEffectiveIds(
669 self.cnxn, self.services, [111])
670 self.assertEqual(effective_ids, {111: {111, 222}})
671
672 self.services.usergroup.TestAddMembers(888, [111])
673 self.services.usergroup.TestAddMembers(999, [222])
674 effective_ids = framework_bizobj.GetEffectiveIds(
675 self.cnxn, self.services, [111])
676 self.assertEqual(effective_ids, {111: {111, 222, 888, 999}})
677
678 def testAccountHasChildren(self):
679 """All linked child effective_ids are added to parent's."""
680 child1 = self.services.user.TestAddUser('child1@example.com', 111)
681 child1.linked_parent_id = 333
682 child2 = self.services.user.TestAddUser('child3@example.com', 222)
683 child2.linked_parent_id = 333
684 parent = self.services.user.TestAddUser('parent@example.com', 333)
685 parent.linked_child_ids = [111, 222]
686
687 effective_ids = framework_bizobj.GetEffectiveIds(
688 self.cnxn, self.services, [333])
689 self.assertEqual(effective_ids, {333: {111, 222, 333}})
690
691 self.services.usergroup.TestAddMembers(888, [111])
692 self.services.usergroup.TestAddMembers(999, [222])
693 effective_ids = framework_bizobj.GetEffectiveIds(
694 self.cnxn, self.services, [333])
695 self.assertEqual(effective_ids, {333: {111, 222, 333, 888, 999}})