Merge lp:~wgrant/launchpad/branchnamespace-information-type into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 15610
Proposed branch: lp:~wgrant/launchpad/branchnamespace-information-type
Merge into: lp:launchpad
Diff against target: 696 lines (+137/-287)
6 files modified
lib/lp/code/errors.py (+0/-10)
lib/lp/code/interfaces/branchnamespace.py (+6/-16)
lib/lp/code/model/branch.py (+6/-9)
lib/lp/code/model/branchnamespace.py (+52/-76)
lib/lp/code/model/tests/test_branch.py (+5/-6)
lib/lp/code/model/tests/test_branchnamespace.py (+68/-170)
To merge this branch: bzr merge lp:~wgrant/launchpad/branchnamespace-information-type
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+114387@code.launchpad.net

Commit message

Start porting IBranchNamespace's privacy methods to information types.

Description of the change

This branch prepares IBranchNamespace for the BranchVisibilityPolicy replacement. Branch privacy is no longer a binary thing; we want to be able to enable different sets of information types depending on new project configuration.

This does not yet change any behaviour. The namespace implementations still allow combinations of PUBLIC_INFORMATION_TYPES and PRIVATE_INFORMATION_TYPES, and ProductNamespace still uses BranchVisibilityPolicy. But it's the majority of the work toward an interface that can operate on both BVP and the new config system.

Some callsites are only minimally shimmed around the new getAllowedInformationTypes method. A more complete port will come in a subsequent branch.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/errors.py'
--- lib/lp/code/errors.py 2012-05-24 02:16:59 +0000
+++ lib/lp/code/errors.py 2012-07-11 12:28:19 +0000
@@ -8,8 +8,6 @@
8 'AlreadyLatestFormat',8 'AlreadyLatestFormat',
9 'BadBranchMergeProposalSearchContext',9 'BadBranchMergeProposalSearchContext',
10 'BadStateTransition',10 'BadStateTransition',
11 'BranchCannotBePrivate',
12 'BranchCannotBePublic',
13 'BranchCannotChangeInformationType',11 'BranchCannotChangeInformationType',
14 'BranchCreationException',12 'BranchCreationException',
15 'BranchCreationForbidden',13 'BranchCreationForbidden',
@@ -148,14 +146,6 @@
148 """146 """
149147
150148
151class BranchCannotBePublic(Exception):
152 """The branch cannot be made public."""
153
154
155class BranchCannotBePrivate(Exception):
156 """The branch cannot be made private."""
157
158
159class BranchCannotChangeInformationType(Exception):149class BranchCannotChangeInformationType(Exception):
160 """The information type of this branch cannot be changed."""150 """The information type of this branch cannot be changed."""
161151
162152
=== modified file 'lib/lp/code/interfaces/branchnamespace.py'
--- lib/lp/code/interfaces/branchnamespace.py 2011-03-03 01:13:47 +0000
+++ lib/lp/code/interfaces/branchnamespace.py 2012-07-11 12:28:19 +0000
@@ -110,6 +110,12 @@
110 :return: A Boolean value.110 :return: A Boolean value.
111 """111 """
112112
113 def getAllowedInformationTypes():
114 """Get the information types that a branch in this namespace can have.
115
116 :return: A sequence of `InformationType`s.
117 """
118
113 def areNewBranchesPrivate():119 def areNewBranchesPrivate():
114 """Are new branches in this namespace private?120 """Are new branches in this namespace private?
115121
@@ -118,22 +124,6 @@
118 :return: A Boolean value.124 :return: A Boolean value.
119 """125 """
120126
121 def canBranchesBePrivate():
122 """Can branches by the user be private in this namespace?
123
124 No check is made about whether or not a user can create branches.
125
126 :return: A Boolean value.
127 """
128
129 def canBranchesBePublic():
130 """Can branches by the user be public in this namespace?
131
132 No check is made about whether or not a user can create branches.
133
134 :return: A Boolean value.
135 """
136
137 def validateRegistrant(registrant):127 def validateRegistrant(registrant):
138 """Check that the registrant can create a branch on this namespace.128 """Check that the registrant can create a branch on this namespace.
139129
140130
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2012-07-10 09:51:13 +0000
+++ lib/lp/code/model/branch.py 2012-07-11 12:28:19 +0000
@@ -83,8 +83,6 @@
83 )83 )
84from lp.code.errors import (84from lp.code.errors import (
85 AlreadyLatestFormat,85 AlreadyLatestFormat,
86 BranchCannotBePrivate,
87 BranchCannotBePublic,
88 BranchCannotChangeInformationType,86 BranchCannotChangeInformationType,
89 BranchMergeProposalExists,87 BranchMergeProposalExists,
90 BranchTargetError,88 BranchTargetError,
@@ -248,14 +246,11 @@
248 and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES246 and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES
249 and information_type in PUBLIC_INFORMATION_TYPES):247 and information_type in PUBLIC_INFORMATION_TYPES):
250 raise BranchCannotChangeInformationType()248 raise BranchCannotChangeInformationType()
251 private = information_type in PRIVATE_INFORMATION_TYPES
252 # Only check the privacy policy if the user is not special.249 # Only check the privacy policy if the user is not special.
253 if verify_policy and not user_has_special_branch_access(who):250 if verify_policy and not user_has_special_branch_access(who):
254 policy = IBranchNamespacePolicy(self.namespace)251 policy = IBranchNamespacePolicy(self.namespace)
255 if private and not policy.canBranchesBePrivate():252 if information_type not in policy.getAllowedInformationTypes():
256 raise BranchCannotBePrivate()253 raise BranchCannotChangeInformationType()
257 if not private and not policy.canBranchesBePublic():
258 raise BranchCannotBePublic()
259 self.information_type = information_type254 self.information_type = information_type
260 self._reconcileAccess()255 self._reconcileAccess()
261 if information_type in PRIVATE_INFORMATION_TYPES:256 if information_type in PRIVATE_INFORMATION_TYPES:
@@ -1300,13 +1295,15 @@
1300 def canBePublic(self, user):1295 def canBePublic(self, user):
1301 """See `IBranch`."""1296 """See `IBranch`."""
1302 policy = IBranchNamespacePolicy(self.namespace)1297 policy = IBranchNamespacePolicy(self.namespace)
1303 return policy.canBranchesBePublic()1298 return InformationType.PUBLIC in policy.getAllowedInformationTypes()
13041299
1305 def canBePrivate(self, user):1300 def canBePrivate(self, user):
1306 """See `IBranch`."""1301 """See `IBranch`."""
1307 policy = IBranchNamespacePolicy(self.namespace)1302 policy = IBranchNamespacePolicy(self.namespace)
1308 # Do the easy checks first.1303 # Do the easy checks first.
1309 if (policy.canBranchesBePrivate() or1304 policy_allows = (
1305 InformationType.USERDATA in policy.getAllowedInformationTypes())
1306 if (policy_allows or
1310 user_has_special_branch_access(user) or1307 user_has_special_branch_access(user) or
1311 user.visibility == PersonVisibility.PRIVATE):1308 user.visibility == PersonVisibility.PRIVATE):
1312 return True1309 return True
13131310
=== modified file 'lib/lp/code/model/branchnamespace.py'
--- lib/lp/code/model/branchnamespace.py 2012-06-14 09:09:59 +0000
+++ lib/lp/code/model/branchnamespace.py 2012-07-11 12:28:19 +0000
@@ -44,7 +44,11 @@
44 )44 )
45from lp.code.interfaces.branchtarget import IBranchTarget45from lp.code.interfaces.branchtarget import IBranchTarget
46from lp.code.model.branch import Branch46from lp.code.model.branch import Branch
47from lp.registry.enums import InformationType47from lp.registry.enums import (
48 InformationType,
49 PRIVATE_INFORMATION_TYPES,
50 PUBLIC_INFORMATION_TYPES,
51 )
48from lp.registry.errors import (52from lp.registry.errors import (
49 NoSuchDistroSeries,53 NoSuchDistroSeries,
50 NoSuchSourcePackageName,54 NoSuchSourcePackageName,
@@ -168,7 +172,7 @@
168 "%s cannot create branches owned by %s"172 "%s cannot create branches owned by %s"
169 % (registrant.displayname, owner.displayname))173 % (registrant.displayname, owner.displayname))
170174
171 if not self.checkCreationPolicy(registrant):175 if not self.getAllowedInformationTypes():
172 raise BranchCreationForbidden(176 raise BranchCreationForbidden(
173 'You cannot create branches in "%s"' % self.name)177 'You cannot create branches in "%s"' % self.name)
174178
@@ -261,30 +265,18 @@
261 else:265 else:
262 return True266 return True
263267
268 def getAllowedInformationTypes(self):
269 """See `IBranchNamespace`."""
270 raise NotImplementedError
271
264 def areNewBranchesPrivate(self):272 def areNewBranchesPrivate(self):
265 """See `IBranchNamespace`."""273 """See `IBranchNamespace`."""
266 # Always delegates to canBranchesBePrivate for now.274 return InformationType.USERDATA in self.getAllowedInformationTypes()
267 return self.canBranchesBePrivate()
268
269 def canBranchesBePrivate(self):
270 """See `IBranchNamespace`."""
271 raise NotImplementedError(self.canBranchesBePrivate)
272
273 def canBranchesBePublic(self):
274 """See `IBranchNamespace`."""
275 raise NotImplementedError(self.canBranchesBePublic)
276275
277 def getPrivacySubscriber(self):276 def getPrivacySubscriber(self):
278 """See `IBranchNamespace`."""277 """See `IBranchNamespace`."""
279 raise NotImplementedError(self.getPrivacySubscriber)278 raise NotImplementedError(self.getPrivacySubscriber)
280279
281 def checkCreationPolicy(self, user):
282 """Check to see if user is allowed a branch in this namespace.
283
284 :return: True if the user is allowed, False otherwise.
285 """
286 raise NotImplementedError(self.checkCreationPolicy)
287
288280
289class PersonalNamespace(_BaseNamespace):281class PersonalNamespace(_BaseNamespace):
290 """A namespace for personal (or 'junk') branches.282 """A namespace for personal (or 'junk') branches.
@@ -307,26 +299,19 @@
307 """See `IBranchNamespace`."""299 """See `IBranchNamespace`."""
308 return '~%s/+junk' % self.owner.name300 return '~%s/+junk' % self.owner.name
309301
310 def canBranchesBePrivate(self):302 def getAllowedInformationTypes(self):
311 """See `IBranchNamespace`."""303 """See `IBranchNamespace`."""
312 private = False304 # Private teams get private branches, everyone else gets public ones.
313 if self.owner.is_team and (305 if (self.owner.is_team
314 self.owner.visibility == PersonVisibility.PRIVATE):306 and self.owner.visibility == PersonVisibility.PRIVATE):
315 private = True307 return PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES
316 return private308 else:
317309 return PUBLIC_INFORMATION_TYPES
318 def canBranchesBePublic(self):
319 """See `IBranchNamespace`."""
320 return True
321310
322 def getPrivacySubscriber(self):311 def getPrivacySubscriber(self):
323 """See `IBranchNamespace`."""312 """See `IBranchNamespace`."""
324 return None313 return None
325314
326 def checkCreationPolicy(self, user):
327 """See `_BaseNamespace`."""
328 return True
329
330 @property315 @property
331 def target(self):316 def target(self):
332 """See `IBranchNamespace`."""317 """See `IBranchNamespace`."""
@@ -388,40 +373,39 @@
388 else:373 else:
389 return None374 return None
390375
391 def checkCreationPolicy(self, user):376 def getAllowedInformationTypes(self):
392 """See `_BaseNamespace`."""
393 if len(self._getRelatedPolicies()) > 0:
394 return True
395 base_rule = self.product.getBaseBranchVisibilityRule()
396 return base_rule == BranchVisibilityRule.PUBLIC
397
398 def canBranchesBePrivate(self):
399 """See `IBranchNamespace`."""377 """See `IBranchNamespace`."""
400 # If there is a rule for the namespace owner, use that.378 private_rules = (
401 private = (
402 BranchVisibilityRule.PRIVATE,379 BranchVisibilityRule.PRIVATE,
403 BranchVisibilityRule.PRIVATE_ONLY)380 BranchVisibilityRule.PRIVATE_ONLY)
404 rule = self.product.getBranchVisibilityRuleForTeam(self.owner)381
405 if rule is not None:382 rule = self.product.getBranchVisibilityRuleForTeam(self.owner)
406 return rule in private383 if rule is not None:
407 # If the owner is a member of any team that has a PRIVATE or384 # If there is an explicit rule for the namespace owner, use that.
408 # PRIVATE_ONLY rule, then the branches are private.385 private = rule in private_rules
409 return len(self._getRelatedPrivatePolicies()) > 0386 public = rule != BranchVisibilityRule.PRIVATE_ONLY
410387 else:
411 def canBranchesBePublic(self):388 # Otherwise find all the rules for the owner's teams.
412 """See `IBranchNamespace`."""389 related_rules = set(p.rule for p in self._getRelatedPolicies())
413 # If there is an explicit rule for the namespace owner, use that.390
414 rule = self.product.getBranchVisibilityRuleForTeam(self.owner)391 # If any of the rules allow private branches, allow them.
415 if rule is not None:392 private = bool(related_rules.intersection(private_rules))
416 return rule != BranchVisibilityRule.PRIVATE_ONLY393
417 # If there is another policy that allows public, then branches can be394 # If any of the rules allow public branches, allow them.
418 # public.395 if related_rules.difference([BranchVisibilityRule.PRIVATE_ONLY]):
419 for policy in self._getRelatedPolicies():396 public = True
420 if policy.rule != BranchVisibilityRule.PRIVATE_ONLY:397 else:
421 return True398 # There's no team-specific rules, or none of them allow
422 # If the default is public, then we can have public branches.399 # public branches. Fall back to the default rule.
423 base_rule = self.product.getBaseBranchVisibilityRule()400 base_rule = self.product.getBaseBranchVisibilityRule()
424 return base_rule == BranchVisibilityRule.PUBLIC401 public = base_rule == BranchVisibilityRule.PUBLIC
402
403 types = []
404 if public:
405 types.extend(PUBLIC_INFORMATION_TYPES)
406 if private:
407 types.extend(PRIVATE_INFORMATION_TYPES)
408 return types
425409
426410
427class PackageNamespace(_BaseNamespace):411class PackageNamespace(_BaseNamespace):
@@ -453,22 +437,14 @@
453 """See `IBranchNamespace`."""437 """See `IBranchNamespace`."""
454 return IBranchTarget(self.sourcepackage)438 return IBranchTarget(self.sourcepackage)
455439
456 def canBranchesBePrivate(self):440 def getAllowedInformationTypes(self):
457 """See `IBranchNamespace`."""441 """See `IBranchNamespace`."""
458 return False442 return PUBLIC_INFORMATION_TYPES
459
460 def canBranchesBePublic(self):
461 """See `IBranchNamespace`."""
462 return True
463443
464 def getPrivacySubscriber(self):444 def getPrivacySubscriber(self):
465 """See `IBranchNamespace`."""445 """See `IBranchNamespace`."""
466 return None446 return None
467447
468 def checkCreationPolicy(self, user):
469 """See `_BaseNamespace`."""
470 return True
471
472448
473class BranchNamespaceSet:449class BranchNamespaceSet:
474 """Only implementation of `IBranchNamespaceSet`."""450 """Only implementation of `IBranchNamespaceSet`."""
475451
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2012-07-09 00:18:47 +0000
+++ lib/lp/code/model/tests/test_branch.py 2012-07-11 12:28:19 +0000
@@ -54,8 +54,6 @@
54 )54 )
55from lp.code.errors import (55from lp.code.errors import (
56 AlreadyLatestFormat,56 AlreadyLatestFormat,
57 BranchCannotBePrivate,
58 BranchCannotBePublic,
59 BranchCannotChangeInformationType,57 BranchCannotChangeInformationType,
60 BranchCreatorNotMemberOfOwnerTeam,58 BranchCreatorNotMemberOfOwnerTeam,
61 BranchCreatorNotOwner,59 BranchCreatorNotOwner,
@@ -2419,10 +2417,10 @@
24192417
2420 def test_public_to_private_not_allowed(self):2418 def test_public_to_private_not_allowed(self):
2421 # If there are no privacy policies allowing private branches, then2419 # If there are no privacy policies allowing private branches, then
2422 # BranchCannotBePrivate is rasied.2420 # BranchCannotChangeInformationType is rasied.
2423 branch = self.factory.makeProductBranch()2421 branch = self.factory.makeProductBranch()
2424 self.assertRaises(2422 self.assertRaises(
2425 BranchCannotBePrivate,2423 BranchCannotChangeInformationType,
2426 branch.setPrivate,2424 branch.setPrivate,
2427 True, branch.owner)2425 True, branch.owner)
24282426
@@ -2460,7 +2458,8 @@
24602458
2461 def test_private_to_public_not_allowed(self):2459 def test_private_to_public_not_allowed(self):
2462 # If the namespace policy does not allow public branches, attempting2460 # If the namespace policy does not allow public branches, attempting
2463 # to change the branch to be public raises BranchCannotBePublic.2461 # to change the branch to be public raises
2462 # BranchCannotChangeInformationType.
2464 branch = self.factory.makeProductBranch(2463 branch = self.factory.makeProductBranch(
2465 information_type=InformationType.USERDATA)2464 information_type=InformationType.USERDATA)
2466 branch.product.setBranchVisibilityTeamPolicy(2465 branch.product.setBranchVisibilityTeamPolicy(
@@ -2468,7 +2467,7 @@
2468 branch.product.setBranchVisibilityTeamPolicy(2467 branch.product.setBranchVisibilityTeamPolicy(
2469 branch.owner, BranchVisibilityRule.PRIVATE_ONLY)2468 branch.owner, BranchVisibilityRule.PRIVATE_ONLY)
2470 self.assertRaises(2469 self.assertRaises(
2471 BranchCannotBePublic,2470 BranchCannotChangeInformationType,
2472 branch.setPrivate,2471 branch.setPrivate,
2473 False, branch.owner)2472 False, branch.owner)
24742473
24752474
=== modified file 'lib/lp/code/model/tests/test_branchnamespace.py'
--- lib/lp/code/model/tests/test_branchnamespace.py 2012-06-08 06:01:50 +0000
+++ lib/lp/code/model/tests/test_branchnamespace.py 2012-07-11 12:28:19 +0000
@@ -35,7 +35,11 @@
35 PersonalNamespace,35 PersonalNamespace,
36 ProductNamespace,36 ProductNamespace,
37 )37 )
38from lp.registry.enums import InformationType38from lp.registry.enums import (
39 InformationType,
40 PRIVATE_INFORMATION_TYPES,
41 PUBLIC_INFORMATION_TYPES,
42 )
39from lp.registry.errors import (43from lp.registry.errors import (
40 NoSuchDistroSeries,44 NoSuchDistroSeries,
41 NoSuchSourcePackageName,45 NoSuchSourcePackageName,
@@ -974,8 +978,8 @@
974 BranchVisibilityRule.PRIVATE_ONLY)978 BranchVisibilityRule.PRIVATE_ONLY)
975979
976980
977class TestPersonalNamespaceCanBranchesBePrivate(TestCaseWithFactory):981class TestPersonalNamespaceAllowedInformationTypes(TestCaseWithFactory):
978 """Tests for PersonalNamespace.canBranchesBePrivate."""982 """Tests for PersonalNamespace.getAllowedInformationTypes."""
979983
980 layer = DatabaseFunctionalLayer984 layer = DatabaseFunctionalLayer
981985
@@ -983,61 +987,44 @@
983 # +junk branches are not private for individuals987 # +junk branches are not private for individuals
984 person = self.factory.makePerson()988 person = self.factory.makePerson()
985 namespace = PersonalNamespace(person)989 namespace = PersonalNamespace(person)
986 self.assertFalse(namespace.canBranchesBePrivate())990 self.assertContentEqual(
991 PUBLIC_INFORMATION_TYPES,
992 namespace.getAllowedInformationTypes())
987993
988 def test_public_team(self):994 def test_public_team(self):
989 # +junk branches for public teams cannot be private995 # +junk branches for public teams cannot be private
990 team = self.factory.makeTeam()996 team = self.factory.makeTeam()
991 namespace = PersonalNamespace(team)997 namespace = PersonalNamespace(team)
992 self.assertFalse(namespace.canBranchesBePrivate())998 self.assertContentEqual(
999 PUBLIC_INFORMATION_TYPES,
1000 namespace.getAllowedInformationTypes())
9931001
994 def test_private_team(self):1002 def test_private_team(self):
995 # +junk branches can be private for private teams1003 # +junk branches can be private or public for private teams
996 team = self.factory.makeTeam(visibility=PersonVisibility.PRIVATE)1004 team = self.factory.makeTeam(visibility=PersonVisibility.PRIVATE)
997 namespace = PersonalNamespace(team)1005 namespace = PersonalNamespace(team)
998 self.assertTrue(namespace.canBranchesBePrivate())1006 self.assertContentEqual(
9991007 PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES,
10001008 namespace.getAllowedInformationTypes())
1001class TestPersonalNamespaceCanBranchesBePublic(TestCaseWithFactory):1009
1002 """Tests for PersonalNamespace.canBranchesBePublic."""1010
10031011class TestPackageNamespaceAllowedInformationTypes(TestCaseWithFactory):
1004 layer = DatabaseFunctionalLayer1012 """Tests for PackageNamespace.getAllowedInformationTypes."""
10051013
1006 def test_anyone(self):1014 layer = DatabaseFunctionalLayer
1007 # All +junk branches are public.1015
1008 person = self.factory.makePerson()1016 def test_anyone(self):
1009 namespace = PersonalNamespace(person)1017 # Source package branches are always public.
1010 self.assertTrue(namespace.canBranchesBePublic())1018 source_package = self.factory.makeSourcePackage()
10111019 person = self.factory.makePerson()
10121020 namespace = PackageNamespace(person, source_package)
1013class TestPackageNamespaceCanBranchesBePrivate(TestCaseWithFactory):1021 self.assertContentEqual(
1014 """Tests for PackageNamespace.canBranchesBePrivate."""1022 PUBLIC_INFORMATION_TYPES,
10151023 namespace.getAllowedInformationTypes())
1016 layer = DatabaseFunctionalLayer1024
10171025
1018 def test_anyone(self):1026class TestProductNamespaceAllowedInformationTypes(TestCaseWithFactory):
1019 # No source package branches are private.1027 """Tests for ProductNamespace.getAllowedInformationTypes."""
1020 source_package = self.factory.makeSourcePackage()
1021 person = self.factory.makePerson()
1022 namespace = PackageNamespace(person, source_package)
1023 self.assertFalse(namespace.canBranchesBePrivate())
1024
1025
1026class TestPackageNamespaceCanBranchesBePublic(TestCaseWithFactory):
1027 """Tests for PackageNamespace.canBranchesBePublic."""
1028
1029 layer = DatabaseFunctionalLayer
1030
1031 def test_anyone(self):
1032 # All source package branches are public.
1033 source_package = self.factory.makeSourcePackage()
1034 person = self.factory.makePerson()
1035 namespace = PackageNamespace(person, source_package)
1036 self.assertTrue(namespace.canBranchesBePublic())
1037
1038
1039class TestProductNamespaceCanBranchesBePrivate(TestCaseWithFactory):
1040 """Tests for ProductNamespace.canBranchesBePrivate."""
10411028
1042 layer = DatabaseFunctionalLayer1029 layer = DatabaseFunctionalLayer
10431030
@@ -1048,33 +1035,26 @@
1048 def _getNamespace(self, owner):1035 def _getNamespace(self, owner):
1049 return ProductNamespace(owner, self.product)1036 return ProductNamespace(owner, self.product)
10501037
1051 def assertNewBranchesPublic(self, owner):1038 def assertTypes(self, owner, types):
1052 # Assert that new branches in the owner namespace are public.1039 namespace = self._getNamespace(owner)
1053 namespace = self._getNamespace(owner)1040 self.assertContentEqual(types, namespace.getAllowedInformationTypes())
1054 self.assertFalse(namespace.canBranchesBePrivate())
1055
1056 def assertNewBranchesPrivate(self, owner):
1057 # Assert that new branches in the owner namespace are private.
1058 namespace = self._getNamespace(owner)
1059 self.assertTrue(namespace.canBranchesBePrivate())
10601041
1061 def test_no_policies(self):1042 def test_no_policies(self):
1062 # If there are no defined policies, any personal branch is not1043 # If there are no defined policies, any personal branch is not
1063 # private.1044 # private.
1064 self.assertNewBranchesPublic(self.factory.makePerson())1045 self.assertTypes(self.factory.makePerson(), PUBLIC_INFORMATION_TYPES)
10651046
1066 def test_any_person_with_public_base_rule(self):1047 def test_any_person_with_public_base_rule(self):
1067 # If the base visibility rule is PUBLIC, then new branches are public.1048 # If the base visibility rule is PUBLIC, then new branches are public.
1068 self.product.setBranchVisibilityTeamPolicy(1049 self.product.setBranchVisibilityTeamPolicy(
1069 None, BranchVisibilityRule.PUBLIC)1050 None, BranchVisibilityRule.PUBLIC)
1070 self.assertNewBranchesPublic(self.factory.makePerson())1051 self.assertTypes(self.factory.makePerson(), PUBLIC_INFORMATION_TYPES)
10711052
1072 def test_any_person_with_forbidden_base_rule(self):1053 def test_any_person_with_forbidden_base_rule(self):
1073 # If the base visibility rule is FORBIDDEN, new branches are still1054 # If the base visibility rule is FORBIDDEN, there are no legal types.
1074 # considered public.
1075 self.product.setBranchVisibilityTeamPolicy(1055 self.product.setBranchVisibilityTeamPolicy(
1076 None, BranchVisibilityRule.FORBIDDEN)1056 None, BranchVisibilityRule.FORBIDDEN)
1077 self.assertNewBranchesPublic(self.factory.makePerson())1057 self.assertTypes(self.factory.makePerson(), [])
10781058
1079 def test_team_member_with_private_rule(self):1059 def test_team_member_with_private_rule(self):
1080 # If a person is a member of a team that has a PRIVATE rule, then new1060 # If a person is a member of a team that has a PRIVATE rule, then new
@@ -1083,8 +1063,10 @@
1083 team = self.factory.makeTeam(owner=person)1063 team = self.factory.makeTeam(owner=person)
1084 self.product.setBranchVisibilityTeamPolicy(1064 self.product.setBranchVisibilityTeamPolicy(
1085 team, BranchVisibilityRule.PRIVATE)1065 team, BranchVisibilityRule.PRIVATE)
1086 self.assertNewBranchesPrivate(person)1066 self.assertTypes(
1087 self.assertNewBranchesPrivate(team)1067 person, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
1068 self.assertTypes(
1069 team, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
10881070
1089 def test_team_member_with_private_only_rule(self):1071 def test_team_member_with_private_only_rule(self):
1090 # If a person is a member of a team that has a PRIVATE_ONLY rule, then1072 # If a person is a member of a team that has a PRIVATE_ONLY rule, then
@@ -1092,9 +1074,11 @@
1092 person = self.factory.makePerson()1074 person = self.factory.makePerson()
1093 team = self.factory.makeTeam(owner=person)1075 team = self.factory.makeTeam(owner=person)
1094 self.product.setBranchVisibilityTeamPolicy(1076 self.product.setBranchVisibilityTeamPolicy(
1077 None, BranchVisibilityRule.FORBIDDEN)
1078 self.product.setBranchVisibilityTeamPolicy(
1095 team, BranchVisibilityRule.PRIVATE_ONLY)1079 team, BranchVisibilityRule.PRIVATE_ONLY)
1096 self.assertNewBranchesPrivate(person)1080 self.assertTypes(person, PRIVATE_INFORMATION_TYPES)
1097 self.assertNewBranchesPrivate(team)1081 self.assertTypes(team, PRIVATE_INFORMATION_TYPES)
10981082
1099 def test_non_team_member_with_private_rule(self):1083 def test_non_team_member_with_private_rule(self):
1100 # If a person is a not a member of a team that has a privacy rule,1084 # If a person is a not a member of a team that has a privacy rule,
@@ -1103,7 +1087,7 @@
1103 team = self.factory.makeTeam(owner=person)1087 team = self.factory.makeTeam(owner=person)
1104 self.product.setBranchVisibilityTeamPolicy(1088 self.product.setBranchVisibilityTeamPolicy(
1105 team, BranchVisibilityRule.PRIVATE)1089 team, BranchVisibilityRule.PRIVATE)
1106 self.assertNewBranchesPublic(self.factory.makePerson())1090 self.assertTypes(self.factory.makePerson(), PUBLIC_INFORMATION_TYPES)
11071091
1108 def test_team_member_with_multiple_private_rules(self):1092 def test_team_member_with_multiple_private_rules(self):
1109 # If a person is a member of multiple teams that has a privacy rules,1093 # If a person is a member of multiple teams that has a privacy rules,
@@ -1115,9 +1099,12 @@
1115 team_1, BranchVisibilityRule.PRIVATE)1099 team_1, BranchVisibilityRule.PRIVATE)
1116 self.product.setBranchVisibilityTeamPolicy(1100 self.product.setBranchVisibilityTeamPolicy(
1117 team_2, BranchVisibilityRule.PRIVATE)1101 team_2, BranchVisibilityRule.PRIVATE)
1118 self.assertNewBranchesPrivate(person)1102 self.assertTypes(
1119 self.assertNewBranchesPrivate(team_1)1103 person, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
1120 self.assertNewBranchesPrivate(team_2)1104 self.assertTypes(
1105 team_1, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
1106 self.assertTypes(
1107 team_2, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
11211108
1122 def test_team_member_with_multiple_differing_private_rules(self):1109 def test_team_member_with_multiple_differing_private_rules(self):
1123 # If a person is a member of multiple teams that has a privacy rules,1110 # If a person is a member of multiple teams that has a privacy rules,
@@ -1131,103 +1118,12 @@
1131 private_team, BranchVisibilityRule.PRIVATE)1118 private_team, BranchVisibilityRule.PRIVATE)
1132 self.product.setBranchVisibilityTeamPolicy(1119 self.product.setBranchVisibilityTeamPolicy(
1133 public_team, BranchVisibilityRule.PUBLIC)1120 public_team, BranchVisibilityRule.PUBLIC)
1134 self.assertNewBranchesPrivate(person)1121 self.assertTypes(
1135 self.assertNewBranchesPrivate(private_team)1122 person, PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
1136 self.assertNewBranchesPublic(public_team)1123 self.assertTypes(
11371124 private_team,
11381125 PUBLIC_INFORMATION_TYPES + PRIVATE_INFORMATION_TYPES)
1139class TestProductNamespaceCanBranchesBePublic(TestCaseWithFactory):1126 self.assertTypes(public_team, PUBLIC_INFORMATION_TYPES)
1140 """Tests for ProductNamespace.canBranchesBePublic."""
1141
1142 layer = DatabaseFunctionalLayer
1143
1144 def setUp(self):
1145 TestCaseWithFactory.setUp(self)
1146 self.product = self.factory.makeProduct()
1147
1148 def _getNamespace(self, owner):
1149 return ProductNamespace(owner, self.product)
1150
1151 def assertBranchesCanBePublic(self, owner):
1152 # Assert that branches can be public in the owner namespace.
1153 namespace = self._getNamespace(owner)
1154 self.assertTrue(namespace.canBranchesBePublic())
1155
1156 def assertBranchesMustBePrivate(self, owner):
1157 # Assert that branches must be private in the owner namespace.
1158 namespace = self._getNamespace(owner)
1159 self.assertFalse(namespace.canBranchesBePublic())
1160
1161 def test_no_policies(self):
1162 # If there are no defined policies, any branch can be public.
1163 self.assertBranchesCanBePublic(self.factory.makePerson())
1164
1165 def test_any_person_with_public_base_rule(self):
1166 # If the base visibility rule is PUBLIC, any branch can be public
1167 self.product.setBranchVisibilityTeamPolicy(
1168 None, BranchVisibilityRule.PUBLIC)
1169 self.assertBranchesCanBePublic(self.factory.makePerson())
1170
1171 def test_any_person_with_forbidden_base_rule(self):
1172 # If the base visibility rule is FORBIDDEN, branches must be private.
1173 self.product.setBranchVisibilityTeamPolicy(
1174 None, BranchVisibilityRule.FORBIDDEN)
1175 self.assertBranchesMustBePrivate(self.factory.makePerson())
1176
1177 def test_team_member_with_private_rule(self):
1178 # If a person is a member of a team that has a PRIVATE rule then the
1179 # branches can be public even though the default is FORBIDDEN.
1180 person = self.factory.makePerson()
1181 team = self.factory.makeTeam(owner=person)
1182 self.product.setBranchVisibilityTeamPolicy(
1183 None, BranchVisibilityRule.FORBIDDEN)
1184 self.product.setBranchVisibilityTeamPolicy(
1185 team, BranchVisibilityRule.PRIVATE)
1186 self.assertBranchesCanBePublic(person)
1187 self.assertBranchesCanBePublic(team)
1188
1189 def test_team_member_with_private_only_rule(self):
1190 # If a person is a member of a team that has a PRIVATE_ONLY rule, and
1191 # the base rule is FORBIDDEN, then the branches must be private.
1192 person = self.factory.makePerson()
1193 team = self.factory.makeTeam(owner=person)
1194 self.product.setBranchVisibilityTeamPolicy(
1195 None, BranchVisibilityRule.FORBIDDEN)
1196 self.product.setBranchVisibilityTeamPolicy(
1197 team, BranchVisibilityRule.PRIVATE_ONLY)
1198 self.assertBranchesMustBePrivate(person)
1199 self.assertBranchesMustBePrivate(team)
1200
1201 def test_team_member_with_private_only_rule_public_base_rule(self):
1202 # If a person is a member of a team that has a PRIVATE_ONLY rule, and
1203 # the base rule is PUBLIC, then the branches must be private in the
1204 # team namespace, but can be public in the personal namespace.
1205 person = self.factory.makePerson()
1206 team = self.factory.makeTeam(owner=person)
1207 self.product.setBranchVisibilityTeamPolicy(
1208 None, BranchVisibilityRule.PUBLIC)
1209 self.product.setBranchVisibilityTeamPolicy(
1210 team, BranchVisibilityRule.PRIVATE_ONLY)
1211 self.assertBranchesCanBePublic(person)
1212 self.assertBranchesMustBePrivate(team)
1213
1214 def test_team_member_with_multiple_private_rules(self):
1215 # If a person is a member of multiple teams that has a privacy rules,
1216 # then new branches must stay private in any namespace that defines
1217 # PRIVATE_ONLY, but if the team member is a member of any teams that
1218 # specify just PRIVATE, then branches can be made public.
1219 person = self.factory.makePerson()
1220 team_1 = self.factory.makeTeam(owner=person)
1221 team_2 = self.factory.makeTeam(owner=person)
1222 self.product.setBranchVisibilityTeamPolicy(
1223 None, BranchVisibilityRule.FORBIDDEN)
1224 self.product.setBranchVisibilityTeamPolicy(
1225 team_1, BranchVisibilityRule.PRIVATE_ONLY)
1226 self.product.setBranchVisibilityTeamPolicy(
1227 team_2, BranchVisibilityRule.PRIVATE)
1228 self.assertBranchesCanBePublic(person)
1229 self.assertBranchesMustBePrivate(team_1)
1230 self.assertBranchesCanBePublic(team_2)
12311127
12321128
1233class BaseValidateNewBranchMixin:1129class BaseValidateNewBranchMixin:
@@ -1389,7 +1285,8 @@
1389 :param owner: The person or team that will be the owner of the branch.1285 :param owner: The person or team that will be the owner of the branch.
1390 """1286 """
1391 namespace = get_branch_namespace(owner, product=self.product)1287 namespace = get_branch_namespace(owner, product=self.product)
1392 self.assertFalse(namespace.canBranchesBePrivate())1288 self.assertNotIn(
1289 InformationType.USERDATA, namespace.getAllowedInformationTypes())
13931290
1394 def assertPrivateSubscriber(self, creator, owner, subscriber):1291 def assertPrivateSubscriber(self, creator, owner, subscriber):
1395 """Assert that the policy check results in a private branch.1292 """Assert that the policy check results in a private branch.
@@ -1400,7 +1297,8 @@
1400 """1297 """
1401 policy = IBranchNamespacePolicy(1298 policy = IBranchNamespacePolicy(
1402 get_branch_namespace(owner, product=self.product))1299 get_branch_namespace(owner, product=self.product))
1403 self.assertTrue(policy.canBranchesBePrivate())1300 self.assertIn(
1301 InformationType.USERDATA, policy.getAllowedInformationTypes())
1404 if subscriber is None:1302 if subscriber is None:
1405 self.assertIs(None, policy.getPrivacySubscriber())1303 self.assertIs(None, policy.getPrivacySubscriber())
1406 else:1304 else: