Merge lp:~deryck/launchpad/honor-default-for-spec-sharing-policy-1052521 into lp:launchpad

Proposed by Deryck Hodge on 2012-09-18
Status: Merged
Approved by: Deryck Hodge on 2012-09-20
Approved revision: no longer in the source branch.
Merged at revision: 16029
Proposed branch: lp:~deryck/launchpad/honor-default-for-spec-sharing-policy-1052521
Merge into: lp:launchpad
Diff against target: 216 lines (+149/-12)
2 files modified
lib/lp/blueprints/browser/specification.py (+22/-2)
lib/lp/blueprints/browser/tests/test_specification.py (+127/-10)
To merge this branch: bzr merge lp:~deryck/launchpad/honor-default-for-spec-sharing-policy-1052521
Reviewer Review Type Date Requested Status
j.c.sackett (community) 2012-09-18 Approve on 2012-09-20
Review via email: mp+125039@code.launchpad.net

Commit Message

Ensure that default value for information_type when creating new blueprints honors the default for the give specification sharing policy.

Description of the Change

This branch fixes a bug where we were not selecting the correct information type by default when creating a new spec. This is mostly a set of tests to ensure we get the behavior we want, plus some minor changes to the specification form view.

The first change in the browser code is to set an information_type from the default if no value is present in the form data. Purely public or purely proprietary projects will not provide an option to set information_type, so this ensures we get the correct value when saving the form. The other browser code fix is to set initial values with the default, so that this value is selected by default when the form is created. It's just testing after that.

To post a comment you must log in.
j.c.sackett (jcsackett) wrote :

Looks good, Deryck.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/blueprints/browser/specification.py'
2--- lib/lp/blueprints/browser/specification.py 2012-09-20 13:59:25 +0000
3+++ lib/lp/blueprints/browser/specification.py 2012-09-25 19:05:26 +0000
4@@ -123,7 +123,10 @@
5 from lp.blueprints.interfaces.sprintspecification import ISprintSpecification
6 from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
7 from lp.registry.interfaces.distribution import IDistribution
8-from lp.registry.interfaces.product import IProduct
9+from lp.registry.interfaces.product import (
10+ IProduct,
11+ IProductSeries,
12+ )
13 from lp.services.config import config
14 from lp.services.features import getFeatureFlag
15 from lp.services.fields import WorkItemsText
16@@ -244,6 +247,12 @@
17 def register(self, action, data):
18 """Registers a new specification."""
19 self.transform(data)
20+ information_type = data.get('information_type')
21+ if information_type is None and (
22+ IProduct.providedBy(self.context) or
23+ IProductSeries.providedBy(self.context)):
24+ information_type = (
25+ self.context.getDefaultSpecificationInformationType())
26 spec = getUtility(ISpecificationSet).new(
27 owner=self.user,
28 name=data.get('name'),
29@@ -256,7 +265,7 @@
30 approver=data.get('approver'),
31 distribution=data.get('distribution'),
32 definition_status=data.get('definition_status'),
33- information_type=data.get('information_type'))
34+ information_type=information_type)
35 # Propose the specification as a series goal, if specified.
36 series = data.get('series')
37 if series is not None:
38@@ -299,6 +308,17 @@
39 """
40 return self._next_url
41
42+ @property
43+ def initial_values(self):
44+ """Set initial values to honor sharing policy default value."""
45+ information_type = None
46+ if (IProduct.providedBy(self.context) or
47+ IProductSeries.providedBy(self.context)):
48+ information_type = (
49+ self.context.getDefaultSpecificationInformationType())
50+ values = {'information_type': information_type}
51+ return values
52+
53
54 class NewSpecificationFromTargetView(NewSpecificationView):
55 """An abstract view for creating a specification from a target context.
56
57=== modified file 'lib/lp/blueprints/browser/tests/test_specification.py'
58--- lib/lp/blueprints/browser/tests/test_specification.py 2012-09-19 14:09:00 +0000
59+++ lib/lp/blueprints/browser/tests/test_specification.py 2012-09-25 19:05:26 +0000
60@@ -35,6 +35,10 @@
61 )
62 from lp.registry.enums import SpecificationSharingPolicy
63 from lp.registry.interfaces.person import PersonVisibility
64+from lp.registry.interfaces.product import (
65+ IProduct,
66+ IProductSeries,
67+ )
68 from lp.services.features.testing import FeatureFixture
69 from lp.services.webapp.interfaces import BrowserNotificationLevel
70 from lp.services.webapp.publisher import canonical_url
71@@ -465,16 +469,6 @@
72 control.click()
73 return product.getSpecification(self.submitSpec(browser))
74
75- def test_from_product(self):
76- """Creating from a product defaults to PUBLIC."""
77- policy = SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY
78- product = self.factory.makeProduct(
79- specification_sharing_policy=policy)
80- browser = self.getViewBrowser(product, view_name='+addspec')
81- self.assertThat(browser.contents, self.match_it)
82- spec = product.getSpecification(self.submitSpec(browser))
83- self.assertEqual(spec.information_type, InformationType.PUBLIC)
84-
85 def test_supplied_information_types(self):
86 """Creating honours information types."""
87 spec = self.createSpec(
88@@ -526,6 +520,129 @@
89 self.assertThat(browser.contents, Not(self.match_it))
90
91
92+class BaseNewSpecificationInformationTypeDefaultMixin:
93+
94+ layer = DatabaseFunctionalLayer
95+
96+ def _setUp(self):
97+ set_blueprint_information_type(self, True)
98+ it_field = soupmatchers.Tag('it-field', True,
99+ attrs=dict(name='field.information_type'))
100+ self.match_it = soupmatchers.HTMLContains(it_field)
101+
102+ def makeTarget(self, policy, owner=None):
103+ raise NotImplementedError('makeTarget')
104+
105+ def ensurePolicy(self, target, information_type):
106+ """Helper to call _ensurePolicies
107+
108+ Useful because we need to follow to product from
109+ ProductSeries to get to _ensurePolicies.
110+ """
111+ if IProduct.providedBy(target):
112+ removeSecurityProxy(target)._ensurePolicies(information_type)
113+ elif IProductSeries.providedBy(target):
114+ removeSecurityProxy(target.product)._ensurePolicies(
115+ information_type)
116+
117+ def getSpecification(self, target, name):
118+ """Helper to get the specification.
119+
120+ Useful because we need to follow to product from a
121+ ProductSeries.
122+ """
123+ if IProductSeries.providedBy(target):
124+ return target.product.getSpecification(name)
125+ return target.getSpecification(name)
126+
127+ def submitSpec(self, browser):
128+ """Submit a Specification via a browser."""
129+ name = self.factory.getUniqueString()
130+ browser.getControl('Name').value = name
131+ browser.getControl('Title').value = self.factory.getUniqueString()
132+ browser.getControl('Summary').value = self.factory.getUniqueString()
133+ browser.getControl('Register Blueprint').click()
134+ return name
135+
136+ def test_public(self):
137+ """Creating from PUBLIC policy allows only PUBLIC."""
138+ policy = SpecificationSharingPolicy.PUBLIC
139+ target = self.makeTarget(policy)
140+ browser = self.getViewBrowser(target, view_name='+addspec')
141+ self.assertThat(browser.contents, Not(self.match_it))
142+ spec = self.getSpecification(target, self.submitSpec(browser))
143+ self.assertEqual(spec.information_type, InformationType.PUBLIC)
144+
145+ def test_public_or_proprietary(self):
146+ """Creating from PUBLIC_OR_PROPRIETARY defaults to PUBLIC."""
147+ policy = SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY
148+ target = self.makeTarget(policy)
149+ browser = self.getViewBrowser(target, view_name='+addspec')
150+ self.assertThat(browser.contents, self.match_it)
151+ spec = self.getSpecification(target, self.submitSpec(browser))
152+ self.assertEqual(spec.information_type, InformationType.PUBLIC)
153+
154+ def test_proprietary_or_public(self):
155+ """Creating from PROPRIETARY_OR_PUBLIC defaults to PROPRIETARY."""
156+ policy = SpecificationSharingPolicy.PROPRIETARY_OR_PUBLIC
157+ owner = self.factory.makePerson()
158+ target = self.makeTarget(policy, owner=owner)
159+ self.ensurePolicy(target, [InformationType.PROPRIETARY])
160+ browser = self.getViewBrowser(
161+ target, view_name='+addspec', user=owner)
162+ self.assertThat(browser.contents, self.match_it)
163+ spec = self.getSpecification(target, self.submitSpec(browser))
164+ self.assertEqual(spec.information_type, InformationType.PROPRIETARY)
165+
166+ def test_proprietary(self):
167+ """PROPRIETARY only allows proprietary when creating blueprints."""
168+ policy = SpecificationSharingPolicy.PROPRIETARY
169+ owner = self.factory.makePerson()
170+ target = self.makeTarget(policy, owner=owner)
171+ self.ensurePolicy(target, [InformationType.PROPRIETARY])
172+ browser = self.getViewBrowser(
173+ target, view_name='+addspec', user=owner)
174+ self.assertThat(browser.contents, Not(self.match_it))
175+ spec = self.getSpecification(target, self.submitSpec(browser))
176+ self.assertEqual(spec.information_type, InformationType.PROPRIETARY)
177+
178+ def test_embargoed_or_proprietary(self):
179+ """Creating from EMBARGOED_OR_PROPRIETARY defaults to embargoed."""
180+ policy = SpecificationSharingPolicy.EMBARGOED_OR_PROPRIETARY
181+ owner = self.factory.makePerson()
182+ target = self.makeTarget(policy, owner=owner)
183+ self.ensurePolicy(target, [InformationType.EMBARGOED])
184+ browser = self.getViewBrowser(
185+ target, view_name='+addspec', user=owner)
186+ self.assertThat(browser.contents, self.match_it)
187+ spec = self.getSpecification(target, self.submitSpec(browser))
188+ self.assertEqual(spec.information_type, InformationType.EMBARGOED)
189+
190+
191+
192+class TestNewSpecificationDefaultInformationTypeProduct(
193+ BrowserTestCase, BaseNewSpecificationInformationTypeDefaultMixin):
194+
195+ def makeTarget(self, policy, owner=None):
196+ self._setUp()
197+ if owner is None:
198+ owner = self.factory.makePerson()
199+ return self.factory.makeProduct(
200+ owner=owner, specification_sharing_policy=policy)
201+
202+
203+class TestNewSpecificationDefaultInformationTypeProductSeries(
204+ BrowserTestCase, BaseNewSpecificationInformationTypeDefaultMixin):
205+
206+ def makeTarget(self, policy, owner=None):
207+ self._setUp()
208+ if owner is None:
209+ owner = self.factory.makePerson()
210+ product = self.factory.makeProduct(
211+ owner=owner, specification_sharing_policy=policy)
212+ return self.factory.makeProductSeries(product=product)
213+
214+
215 class TestSpecificationViewPrivateArtifacts(BrowserTestCase):
216 """ Tests that specifications with private team artifacts can be viewed.
217