Merge lp:~adeuring/launchpad/security-guarded-test-object-factory-2 into lp:launchpad

Proposed by Abel Deuring
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 11208
Proposed branch: lp:~adeuring/launchpad/security-guarded-test-object-factory-2
Merge into: lp:launchpad
Diff against target: 1025 lines (+286/-62)
24 files modified
lib/lp/code/browser/tests/test_branchlisting.py (+4/-2)
lib/lp/code/browser/tests/test_sourcepackagerecipe.py (+12/-5)
lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py (+4/-1)
lib/lp/code/model/tests/test_branch.py (+4/-1)
lib/lp/code/model/tests/test_linkedbranch.py (+7/-2)
lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+5/-2)
lib/lp/registry/browser/tests/distroseries-views.txt (+1/-1)
lib/lp/registry/browser/tests/milestone-views.txt (+5/-1)
lib/lp/registry/browser/tests/productseries-views.txt (+6/-2)
lib/lp/registry/stories/webservice/xx-project-registry.txt (+4/-2)
lib/lp/registry/tests/test_distroseries.py (+15/-6)
lib/lp/registry/tests/test_sourcepackage.py (+9/-2)
lib/lp/soyuz/adapters/tests/test_packagelocation.py (+4/-1)
lib/lp/soyuz/browser/tests/archive-views.txt (+7/-2)
lib/lp/soyuz/browser/tests/test_distrosourcepackagerelease.py (+7/-1)
lib/lp/soyuz/browser/tests/test_sourcepackagerelease.py (+11/-5)
lib/lp/soyuz/doc/archive.txt (+9/-4)
lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt (+12/-5)
lib/lp/soyuz/tests/test_publishing.py (+9/-3)
lib/lp/testing/factory.py (+85/-9)
lib/lp/testing/tests/test_factory.py (+50/-0)
lib/lp/translations/browser/tests/test_breadcrumbs.py (+3/-1)
lib/lp/translations/doc/translations-export-to-branch.txt (+5/-1)
lib/lp/translations/stories/buildfarm/xx-build-summary.txt (+8/-3)
To merge this branch: bzr merge lp:~adeuring/launchpad/security-guarded-test-object-factory-2
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Review via email: mp+30642@code.launchpad.net

Description of the change

This branch is the second of series with the final goal that all
methods of LaunchpadObjectFactory will return security proxied
objects. Basically, it ensures that the methods
LaunchpadObjectFactory.makeDiff() and
LaunchpadObjectFactory.makeCopyArchiveLocation() return security
proxied objects.

The remaining changes are only calls of the function
remove_security_proxy_and_shout_at_engineer() where necessary and
some lint removal.

See also the merge proposal for the base branch:
https://code.edge.launchpad.net/~adeuring/launchpad/security-guarded-test-object-factory-1/+merge/30497

tests:
./bin/test -vvt lp.soyuz.adapters.tests.test_packagelocation
./bin/test -vvt lp.soyuz.browser.tests.archive-views.txt
./bin/test -vvt lp.soyuz.tests....doc.archive.txt
./bin/test -vvt xx-distribution-archives.txt

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/soyuz/adapters/tests/test_packagelocation.py
  lib/lp/soyuz/browser/tests/archive-views.txt
  lib/lp/soyuz/doc/archive.txt
  lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt
  lib/lp/testing/factory.py

./lib/lp/soyuz/browser/tests/archive-views.txt
       0: narrative uses a moin header.
       8: narrative uses a moin header.
     472: narrative uses a moin header.
     515: narrative uses a moin header.
     642: narrative uses a moin header.
     743: want exceeds 78 characters.
    1025: narrative uses a moin header.
    1302: narrative uses a moin header.
    1368: narrative uses a moin header.
./lib/lp/soyuz/doc/archive.txt
       0: narrative uses a moin header.
     120: narrative exceeds 78 characters.
     282: narrative uses a moin header.
     444: narrative uses a moin header.
     674: narrative uses a moin header.
     714: narrative uses a moin header.
     760: narrative uses a moin header.
     826: narrative uses a moin header.
     933: narrative uses a moin header.
     952: narrative uses a moin header.
    1031: narrative uses a moin header.
    1087: narrative uses a moin header.
    1282: narrative uses a moin header.
    1318: narrative uses a moin header.
    1352: source has bad indentation.
    1854: narrative uses a moin header.
    1998: narrative has trailing whitespace.
    2024: narrative has trailing whitespace.
    2025: narrative has trailing whitespace.
    2037: narrative uses a moin header.
    2054: narrative uses a moin header.
    2057: narrative exceeds 78 characters.
    2071: source exceeds 78 characters.
    2077: narrative exceeds 78 characters.
    2092: narrative exceeds 78 characters.
    2243: narrative uses a moin header.
    2314: narrative uses a moin header.
    2521: narrative uses a moin header.
    2560: narrative uses a moin header.
    2640: narrative uses a moin header.
    2672: narrative uses a moin header.
    2704: narrative uses a moin header.
    2749: narrative uses a moin header.
./lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt
       0: narrative uses a moin header.
./lib/lp/testing/factory.py
     157: 'logout' imported but unused
     837: E231 missing whitespace after ','
    2734: E302 expected 2 blank lines, found 1
    2761: E301 expected 1 blank line, found 0
    1043: Line exceeds 78 characters.
    2735: Line exceeds 78 characters.

I simply did not bother to fix these already existing lint issues.

This branch is based on
lp:~adeuring/launchpad/security-guarded-test-object-factory-1 (reviewed
and approved by jtv) which did not land due to the recent buildbot
failure. The diff against this branch:

=== modified file 'lib/lp/soyuz/adapters/tests/test_packagelocation.py'
--- lib/lp/soyuz/adapters/tests/test_packagelocation.py 2010-06-22 12:08:51 +0000
+++ lib/lp/soyuz/adapters/tests/test_packagelocation.py 2010-07-21 09:52:05 +0000
@@ -12,8 +12,10 @@
 from lp.soyuz.interfaces.archive import ArchivePurpose
 from lp.soyuz.interfaces.component import IComponentSet
 from lp.testing import TestCaseWithFactory
+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
 from canonical.testing import LaunchpadZopelessLayer

+
 class TestPackageLocation(TestCaseWithFactory):
     """Test the `PackageLocation` class."""
     layer = LaunchpadZopelessLayer
@@ -34,7 +36,8 @@
         returned_location = self.factory.makeCopyArchiveLocation(
             distribution=ubuntu, name='now-comes-the-mystery',
             owner=self.factory.makePerson(name='mysteryman'))
- copy_archive = returned_location.archive
+ copy_archive = remove_security_proxy_and_shout_at_engineer(
+ returned_location).archive

         # Now use the created copy archive to test the build_package_location
         # helper (called via getPackageLocation):

=== modified file 'lib/lp/soyuz/browser/tests/archive-views.txt'
--- lib/lp/soyuz/browser/tests/archive-views.txt 2010-05-21 10:59:09 +0000
+++ lib/lp/soyuz/browser/tests/archive-views.txt 2010-07-21 09:55:43 +0000
@@ -15,11 +15,14 @@

     >>> from lp.registry.interfaces.distribution import (
     ... IDistributionSet)
+ >>> from lp.testing.factory import (
+ ... remove_security_proxy_and_shout_at_engineer)
     >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
     >>> copy_location = factory.makeCopyArchiveLocation(
     ... distribution=ubuntu,
     ... name="intrepid-security-rebuild")
- >>> copy_archive = copy_location.archive
+ >>> copy_archive = remove_security_proxy_and_shout_at_engineer(
+ ... copy_location).archive

 And let's create two views to compare:

@@ -65,8 +68,10 @@
     0

     # Create a copy-request to Celso's PPA.
+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
+ ... copy_location)
     >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
- ... copy_location, copy_archive.owner)
+ ... naked_copy_location, copy_archive.owner)

     >>> len(copy_archive_view.package_copy_requests)
     1

=== modified file 'lib/lp/soyuz/doc/archive.txt'
--- lib/lp/soyuz/doc/archive.txt 2010-07-21 09:41:48 +0000
+++ lib/lp/soyuz/doc/archive.txt 2010-07-21 15:47:37 +0000
@@ -1285,10 +1285,15 @@
 The IArchive interface includes a convenience method for creating a
 package copy request:

+ >>> from lp.testing.factory import (
+ ... remove_security_proxy_and_shout_at_engineer)
     >>> requestor = factory.makePerson(name='me-copy')
     >>> copy_target = factory.makeCopyArchiveLocation(
     ... distribution=ubuntu, name='my-copy-archive', owner=requestor)
- >>> pcr = ubuntu.main_archive.requestPackageCopy(copy_target, requestor)
+ >>> naked_copy_target = remove_security_proxy_and_shout_at_engineer(
+ ... copy_target)
+ >>> pcr = ubuntu.main_archive.requestPackageCopy(
+ ... naked_copy_target, requestor)
     >>> print pcr
     Package copy request
     source = primary/hoary/-/RELEASE
@@ -1301,7 +1306,7 @@
 The requestPackageCopy method can also take an optional suite name:

     >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
- ... copy_target, requestor, suite="hoary-updates");
+ ... naked_copy_target, requestor, suite="hoary-updates");
     >>> print package_copy_request
     Package copy request
     source = primary/hoary/-/UPDATES
@@ -1412,9 +1417,9 @@

 COPY archives use a URL format of <distro-name>-<archive-name>:

- >>> print copy_target.archive.is_copy
+ >>> print naked_copy_target.archive.is_copy
     True
- >>> print copy_target.archive.archive_url
+ >>> print naked_copy_target.archive.archive_url
     http://rebuild-test.internal/ubuntu-my-copy-archive/ubuntu

 If the archive is private, the url may be different as private PPAs

=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt'
--- lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2010-01-12 08:24:36 +0000
+++ lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2010-07-21 10:15:28 +0000
@@ -6,6 +6,8 @@
     >>> from canonical.launchpad.interfaces import (
     ... IDistributionSet)
     >>> from lp.registry.interfaces.person import IPersonSet
+ >>> from lp.testing.factory import (
+ ... remove_security_proxy_and_shout_at_engineer)
     >>> login('<email address hidden>')
     >>> ubuntu = getUtility(IDistributionSet)['ubuntu']

@@ -13,18 +15,21 @@
     >>> copy_location = factory.makeCopyArchiveLocation(
     ... distribution=ubuntu, owner=joe,
     ... name="intrepid-security-rebuild")
- >>> copy_archive = copy_location.archive
+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
+ ... copy_location)
+ >>> copy_archive = naked_copy_location.archive
     >>> copy_archive.enabled
     True

     >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
- ... copy_location, copy_archive.owner)
+ ... naked_copy_location, copy_archive.owner)

     >>> nopriv = getUtility(IPersonSet).getByName('no-priv')
     >>> disabled_location = factory.makeCopyArchiveLocation(
     ... distribution=ubuntu, owner=nopriv,
     ... name="disabled-security-rebuild", enabled=False)
- >>> disabled_archive = disabled_location.archive
+ >>> disabled_archive = remove_security_proxy_and_shout_at_engineer(
+ ... disabled_location).archive
     >>> disabled_archive.enabled
     False

@@ -119,12 +124,14 @@
     >>> copy_location = factory.makeCopyArchiveLocation(
     ... distribution=ubuntu,
     ... name="intrepid-private-security-rebuild")
- >>> copy_archive = copy_location.archive
+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
+ ... copy_location)
+ >>> copy_archive = naked_copy_location.archive
     >>> copy_archive.buildd_secret = 'really secret'
     >>> copy_archive.private = True
     >>> copy_archive.owner.displayname = "Harry Potter"
     >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
- ... copy_location, copy_archive.owner)
+ ... naked_copy_location, copy_archive.owner)
     >>> pub_src = stp.getPubSource(
     ... archive=copy_archive, architecturehintlist='any')
     >>> pub_bins = stp.getPubBinaries(pub_source=pub_src)

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-07-21 15:43:07 +0000
+++ lib/lp/testing/factory.py 2010-07-21 15:47:37 +0000
@@ -362,7 +362,7 @@

         location = PackageLocation(copy_archive, distribution, distroseries,
             pocket)
- return location
+ return ProxyFactory(location)

     def makeAccount(self, displayname, email=None, password=None,
                     status=AccountStatus.ACTIVE,
@@ -1040,7 +1040,7 @@
             CodeReviewNotificationLevel.NOEMAIL, subscribed_by)

     def makeDiff(self, diff_text=DIFF):
- return Diff.fromFile(StringIO(diff_text), len(diff_text))
+ return ProxyFactory(Diff.fromFile(StringIO(diff_text), len(diff_text)))

     def makePreviewDiff(self, conflicts=u''):
         diff = self.makeDiff()

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/browser/tests/test_branchlisting.py'
2--- lib/lp/code/browser/tests/test_branchlisting.py 2010-05-28 09:54:45 +0000
3+++ lib/lp/code/browser/tests/test_branchlisting.py 2010-07-22 14:11:16 +0000
4@@ -32,12 +32,14 @@
5 from lp.testing import (
6 BrowserTestCase, TestCase, TestCaseWithFactory, login_person,
7 person_logged_in, time_counter)
8+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
9 from lp.testing.views import create_initialized_view
10 from canonical.launchpad.testing.pages import extract_text, find_tag_by_id
11 from canonical.launchpad.webapp import canonical_url
12 from canonical.launchpad.webapp.servers import LaunchpadTestRequest
13 from canonical.testing.layers import DatabaseFunctionalLayer
14
15+
16 class TestListingToSortOrder(TestCase):
17 """Tests for the BranchSet._listingSortToOrderBy static method.
18
19@@ -60,6 +62,7 @@
20
21 def assertSortsEqual(self, sort_one, sort_two):
22 """Assert that one list of sort specs is equal to another."""
23+
24 def sort_data(sort):
25 return sort.suffix, sort.expr
26 self.assertEqual(map(sort_data, sort_one), map(sort_data, sort_two))
27@@ -352,7 +355,7 @@
28 # series on the main site, not the code site.
29 branch = self.factory.makeProductBranch()
30 series = self.factory.makeProductSeries(product=branch.product)
31- series.branch = branch
32+ remove_security_proxy_and_shout_at_engineer(series).branch = branch
33 browser = self.getUserBrowser(
34 canonical_url(branch.product, rootsite='code'))
35 link = browser.getLink(re.compile('^' + series.name + '$'))
36@@ -402,4 +405,3 @@
37
38 def test_suite():
39 return unittest.TestLoader().loadTestsFromName(__name__)
40-
41
42=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py'
43--- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-07-21 21:16:54 +0000
44+++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-07-22 14:11:16 +0000
45@@ -29,6 +29,7 @@
46 from lp.registry.interfaces.pocket import PackagePublishingPocket
47 from lp.soyuz.model.processor import ProcessorFamily
48 from lp.testing import ANONYMOUS, BrowserTestCase, login, logout
49+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
50
51
52 class TestCaseForRecipe(BrowserTestCase):
53@@ -45,7 +46,9 @@
54 self.squirrel = self.factory.makeDistroSeries(
55 displayname='Secret Squirrel', name='secret', version='100.04',
56 distribution=self.ppa.distribution)
57- self.squirrel.nominatedarchindep = self.squirrel.newArch(
58+ naked_squirrel = remove_security_proxy_and_shout_at_engineer(
59+ self.squirrel)
60+ naked_squirrel.nominatedarchindep = self.squirrel.newArch(
61 'i386', ProcessorFamily.get(1), False, self.chef,
62 supports_virtualized=True)
63
64@@ -494,7 +497,7 @@
65 def makeBuildJob(self, recipe):
66 """Return a build associated with a buildjob."""
67 build = self.factory.makeSourcePackageRecipeBuild(
68- recipe=recipe, distroseries=self.squirrel, archive=self.ppa )
69+ recipe=recipe, distroseries=self.squirrel, archive=self.ppa)
70 self.factory.makeSourcePackageRecipeBuildJob(recipe_build=build)
71 return build
72
73@@ -527,6 +530,7 @@
74 self.assertEqual(
75 set([build1, build2, build3, build4, build5, build6]),
76 set(view.builds))
77+
78 def set_day(build, day):
79 removeSecurityProxy(build).datebuilt = datetime(
80 2010, 03, day, tzinfo=utc)
81@@ -569,7 +573,8 @@
82 woody = self.factory.makeDistroSeries(
83 name='woody', displayname='Woody',
84 distribution=self.ppa.distribution)
85- woody.nominatedarchindep = woody.newArch(
86+ naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
87+ naked_woody.nominatedarchindep = woody.newArch(
88 'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
89 supports_virtualized=True)
90
91@@ -603,7 +608,8 @@
92 woody = self.factory.makeDistroSeries(
93 name='woody', displayname='Woody',
94 distribution=self.ppa.distribution)
95- woody.nominatedarchindep = woody.newArch(
96+ naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
97+ naked_woody.nominatedarchindep = woody.newArch(
98 'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
99 supports_virtualized=True)
100
101@@ -624,7 +630,8 @@
102 woody = self.factory.makeDistroSeries(
103 name='woody', displayname='Woody',
104 distribution=self.ppa.distribution)
105- woody.nominatedarchindep = woody.newArch(
106+ naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
107+ naked_woody.nominatedarchindep = woody.newArch(
108 'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
109 supports_virtualized=True)
110
111
112=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py'
113--- lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py 2010-07-19 09:22:06 +0000
114+++ lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py 2010-07-22 14:11:16 +0000
115@@ -18,6 +18,7 @@
116 from lp.buildmaster.interfaces.buildbase import BuildStatus
117 from lp.soyuz.model.processor import ProcessorFamily
118 from lp.testing import ANONYMOUS, BrowserTestCase, login, logout
119+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
120
121
122 class TestSourcePackageRecipeBuild(BrowserTestCase):
123@@ -36,7 +37,9 @@
124 self.squirrel = self.factory.makeDistroSeries(
125 displayname='Secret Squirrel', name='secret', version='100.04',
126 distribution=self.ppa.distribution)
127- self.squirrel.nominatedarchindep = self.squirrel.newArch(
128+ naked_squirrel = remove_security_proxy_and_shout_at_engineer(
129+ self.squirrel)
130+ naked_squirrel.nominatedarchindep = self.squirrel.newArch(
131 'i386', ProcessorFamily.get(1), False, self.chef,
132 supports_virtualized=True)
133
134
135=== modified file 'lib/lp/code/model/tests/test_branch.py'
136--- lib/lp/code/model/tests/test_branch.py 2010-07-17 23:15:30 +0000
137+++ lib/lp/code/model/tests/test_branch.py 2010-07-22 14:11:16 +0000
138@@ -537,7 +537,7 @@
139 jobs = list(getUtility(IBranchUpgradeJobSource).iterReady())
140 self.assertEqual(
141 jobs,
142- [job,])
143+ [job, ])
144
145 def test_requestUpgrade_no_upgrade_needed(self):
146 # If a branch doesn't need to be upgraded, requestUpgrade raises an
147@@ -635,6 +635,7 @@
148 branch = self.factory.makeProductBranch(
149 product=fooix, owner=eric, name='trunk')
150 linked_branch = ICanHasLinkedBranch(future)
151+ login_person(fooix.owner)
152 linked_branch.setBranch(branch)
153 self.assertEqual(
154 [linked_branch],
155@@ -827,6 +828,7 @@
156 product = branch.product
157 series = self.factory.makeProductSeries(product=product)
158 linked_branch = ICanHasLinkedBranch(series)
159+ login_person(series.owner)
160 linked_branch.setBranch(branch)
161 self.assertBzrIdentity(branch, linked_branch.bzr_path)
162
163@@ -852,6 +854,7 @@
164 removeSecurityProxy(branch.product))
165 series_link = ICanHasLinkedBranch(series)
166 product_link.setBranch(branch)
167+ login_person(series.owner)
168 series_link.setBranch(branch)
169 self.assertBzrIdentity(branch, product_link.bzr_path)
170
171
172=== modified file 'lib/lp/code/model/tests/test_linkedbranch.py'
173--- lib/lp/code/model/tests/test_linkedbranch.py 2010-04-16 15:06:55 +0000
174+++ lib/lp/code/model/tests/test_linkedbranch.py 2010-07-22 14:11:16 +0000
175@@ -18,6 +18,7 @@
176 from lp.registry.interfaces.distroseries import NoSuchDistroSeries
177 from lp.registry.interfaces.pocket import PackagePublishingPocket
178 from lp.testing import run_with_login, TestCaseWithFactory
179+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
180
181
182 class TestProductSeriesLinkedBranch(TestCaseWithFactory):
183@@ -27,7 +28,9 @@
184 def test_branch(self):
185 # The linked branch of a product series is its branch attribute.
186 product_series = self.factory.makeProductSeries()
187- product_series.branch = self.factory.makeProductBranch(
188+ naked_product_series = remove_security_proxy_and_shout_at_engineer(
189+ product_series)
190+ naked_product_series.branch = self.factory.makeProductBranch(
191 product=product_series.product)
192 self.assertEqual(
193 product_series.branch, ICanHasLinkedBranch(product_series).branch)
194@@ -35,9 +38,11 @@
195 def test_setBranch(self):
196 # setBranch sets the linked branch of the product series.
197 product_series = self.factory.makeProductSeries()
198+ naked_product_series = remove_security_proxy_and_shout_at_engineer(
199+ product_series)
200 branch = self.factory.makeProductBranch(
201 product=product_series.product)
202- ICanHasLinkedBranch(product_series).setBranch(branch)
203+ ICanHasLinkedBranch(naked_product_series).setBranch(branch)
204 self.assertEqual(branch, product_series.branch)
205
206 def test_bzr_path(self):
207
208=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
209--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-07-20 12:12:46 +0000
210+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-07-22 14:11:16 +0000
211@@ -37,6 +37,7 @@
212 from lp.soyuz.model.processor import ProcessorFamily
213 from lp.soyuz.tests.soyuzbuilddhelpers import WaitingSlave
214 from lp.testing import ANONYMOUS, login, person_logged_in, TestCaseWithFactory
215+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
216 from lp.testing.fakemethod import FakeMethod
217 from lp.testing.mail_helpers import pop_notifications
218
219@@ -53,7 +54,9 @@
220 distroseries_i386 = distroseries.newArch(
221 'i386', ProcessorFamily.get(1), False, person,
222 supports_virtualized=True)
223- distroseries.nominatedarchindep = distroseries_i386
224+ naked_distroseries = remove_security_proxy_and_shout_at_engineer(
225+ distroseries)
226+ naked_distroseries.nominatedarchindep = distroseries_i386
227
228 return getUtility(ISourcePackageRecipeBuildSource).new(
229 distroseries=distroseries,
230@@ -320,7 +323,7 @@
231 removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
232 IStore(build).flush()
233 build.notify()
234- (message,) = pop_notifications()
235+ (message, ) = pop_notifications()
236 requester = build.requester
237 requester_address = format_address(
238 requester.displayname, requester.preferredemail.email)
239
240=== modified file 'lib/lp/registry/browser/tests/distroseries-views.txt'
241--- lib/lp/registry/browser/tests/distroseries-views.txt 2010-05-24 22:04:19 +0000
242+++ lib/lp/registry/browser/tests/distroseries-views.txt 2010-07-22 14:11:16 +0000
243@@ -196,7 +196,7 @@
244 >>> [field.__name__ for field in view.form_fields]
245 ['displayname', 'title', 'summary', 'description', 'status']
246
247- >>> print view.widgets.get('status')._getFormValue()
248+ >>> print view.widgets.get('status')._getFormValue().title
249 Active Development
250
251
252
253=== modified file 'lib/lp/registry/browser/tests/milestone-views.txt'
254--- lib/lp/registry/browser/tests/milestone-views.txt 2010-06-30 19:37:09 +0000
255+++ lib/lp/registry/browser/tests/milestone-views.txt 2010-07-22 14:11:16 +0000
256@@ -579,9 +579,13 @@
257 The driver of a series that belongs to an `IDerivativeDistribution` is a
258 release manager and can create milestones.
259
260+ >>> from lp.testing.factory import (
261+ ... remove_security_proxy_and_shout_at_engineer)
262 >>> distroseries = factory.makeDistroRelease(name='pumpkin')
263 >>> driver = factory.makePerson(name='a-driver')
264- >>> distroseries.driver = driver
265+ >>> naked_distroseries = remove_security_proxy_and_shout_at_engineer(
266+ ... distroseries)
267+ >>> naked_distroseries.driver = driver
268 >>> login_person(driver)
269
270 >>> form = {
271
272=== modified file 'lib/lp/registry/browser/tests/productseries-views.txt'
273--- lib/lp/registry/browser/tests/productseries-views.txt 2010-06-13 02:01:25 +0000
274+++ lib/lp/registry/browser/tests/productseries-views.txt 2010-07-22 14:11:16 +0000
275@@ -255,6 +255,8 @@
276
277 >>> from datetime import datetime
278 >>> from pytz import UTC
279+ >>> from lp.testing.factory import (
280+ ... remove_security_proxy_and_shout_at_engineer)
281
282 >>> product = factory.makeProduct(name="field", displayname='Field')
283 >>> productseries = factory.makeProductSeries(
284@@ -263,7 +265,9 @@
285
286 # Hack the creation date for testing purposes.
287 >>> test_date = datetime(2009, 05, 01, 19, 34, 24, tzinfo=UTC)
288- >>> productseries.datecreated = test_date
289+ >>> naked_productseries = remove_security_proxy_and_shout_at_engineer(
290+ ... productseries)
291+ >>> naked_productseries.datecreated = test_date
292
293 Users without edit permission cannot access the view.
294
295@@ -470,7 +474,7 @@
296
297 The series status is set to obsolete and the releasefileglob was set to None.
298
299- >>> print productseries.status
300+ >>> print productseries.status.title
301 Obsolete
302 >>> print productseries.releasefileglob
303 None
304
305=== modified file 'lib/lp/registry/stories/webservice/xx-project-registry.txt'
306--- lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-06-14 18:32:58 +0000
307+++ lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-07-22 14:11:16 +0000
308@@ -847,15 +847,17 @@
309 The entry for a project series is available at its canonical URL on the
310 virtual host.
311
312+ >>> from zope.security.proxy import removeSecurityProxy
313 >>> login('test@canonical.com')
314 >>> babadoo_owner = factory.makePerson(name='babadoo-owner')
315 >>> babadoo = factory.makeProduct(name='babadoo', owner=babadoo_owner)
316 >>> foobadoo = factory.makeProductSeries(
317 ... product=babadoo, name='foobadoo', owner=babadoo_owner)
318- >>> foobadoo.summary = u'Foobadoo support for Babadoo'
319+ >>> removeSecurityProxy(foobadoo).summary = (
320+ ... u'Foobadoo support for Babadoo')
321 >>> fooey = factory.makeAnyBranch(
322 ... product=babadoo, name='fooey', owner=babadoo_owner)
323- >>> foobadoo.branch = fooey
324+ >>> removeSecurityProxy(foobadoo).branch = fooey
325 >>> logout()
326
327 >>> babadoo_foobadoo = webservice.get('/babadoo/foobadoo').jsonBody()
328
329=== modified file 'lib/lp/registry/tests/test_distroseries.py'
330--- lib/lp/registry/tests/test_distroseries.py 2010-06-23 23:23:28 +0000
331+++ lib/lp/registry/tests/test_distroseries.py 2010-07-22 14:11:16 +0000
332@@ -24,6 +24,7 @@
333 active_publishing_status, PackagePublishingStatus)
334 from lp.soyuz.model.processor import ProcessorFamilySet
335 from lp.testing import TestCase, TestCaseWithFactory
336+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
337 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
338 from lp.translations.interfaces.translations import (
339 TranslationsBranchImportMode)
340@@ -285,7 +286,9 @@
341 self.linkPackage('hot')
342 self.makeSeriesPackage('cold')
343 product_series = self.linkPackage('cold')
344- product_series.product.bugtraker = self.factory.makeBugTracker()
345+ naked_product_series = remove_security_proxy_and_shout_at_engineer(
346+ product_series)
347+ naked_product_series.product.bugtraker = self.factory.makeBugTracker()
348 packagings = self.series.getPrioritizedlPackagings()
349 names = [packaging.sourcepackagename.name for packaging in packagings]
350 expected = [u'hot', u'cold', u'linked']
351@@ -296,7 +299,9 @@
352 self.linkPackage('translatable')
353 self.makeSeriesPackage('withbranch')
354 product_series = self.linkPackage('withbranch')
355- product_series.branch = self.factory.makeBranch()
356+ naked_product_series = remove_security_proxy_and_shout_at_engineer(
357+ product_series)
358+ naked_product_series.branch = self.factory.makeBranch()
359 packagings = self.series.getPrioritizedlPackagings()
360 names = [packaging.sourcepackagename.name for packaging in packagings]
361 expected = [u'translatable', u'linked', u'withbranch']
362@@ -308,8 +313,10 @@
363 self.linkPackage('translatable')
364 self.makeSeriesPackage('importabletranslatable')
365 product_series = self.linkPackage('importabletranslatable')
366- product_series.branch = self.factory.makeBranch()
367- product_series.translations_autoimport_mode = (
368+ naked_product_series = remove_security_proxy_and_shout_at_engineer(
369+ product_series)
370+ naked_product_series.branch = self.factory.makeBranch()
371+ naked_product_series.translations_autoimport_mode = (
372 TranslationsBranchImportMode.IMPORT_TEMPLATES)
373 packagings = self.series.getPrioritizedlPackagings()
374 names = [packaging.sourcepackagename.name for packaging in packagings]
375@@ -343,7 +350,9 @@
376
377 new_distroseries = (
378 self.factory.makeDistroRelease(name=u"sampleseries"))
379- new_distroseries.hide_all_translations = False
380+ naked_new_distroseries = remove_security_proxy_and_shout_at_engineer(
381+ new_distroseries)
382+ naked_new_distroseries.hide_all_translations = False
383 transaction.commit()
384 translatables = self._get_translatables()
385 self.failUnlessEqual(
386@@ -365,7 +374,7 @@
387 translatables,
388 self._ref_translatables(u"sampleseries")))
389
390- new_distroseries.hide_all_translations = True
391+ naked_new_distroseries.hide_all_translations = True
392 transaction.commit()
393 translatables = self._get_translatables()
394 self.failUnlessEqual(
395
396=== modified file 'lib/lp/registry/tests/test_sourcepackage.py'
397--- lib/lp/registry/tests/test_sourcepackage.py 2010-02-24 03:06:54 +0000
398+++ lib/lp/registry/tests/test_sourcepackage.py 2010-07-22 14:11:16 +0000
399@@ -22,6 +22,7 @@
400 from lp.code.interfaces.seriessourcepackagebranch import (
401 IMakeOfficialBranchLinks)
402 from lp.testing import TestCaseWithFactory
403+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
404 from lp.testing.views import create_initialized_view
405 from canonical.testing.layers import DatabaseFunctionalLayer
406
407@@ -252,11 +253,17 @@
408
409 self.obsolete_productseries = self.factory.makeProductSeries(
410 name='obsolete', product=self.product)
411- self.obsolete_productseries.status = SeriesStatus.OBSOLETE
412+ naked_obsolete_productseries = (
413+ remove_security_proxy_and_shout_at_engineer(
414+ self.obsolete_productseries))
415+ naked_obsolete_productseries.status = SeriesStatus.OBSOLETE
416
417 self.dev_productseries = self.factory.makeProductSeries(
418 name='current', product=self.product)
419- self.dev_productseries.status = SeriesStatus.DEVELOPMENT
420+ naked_dev_productseries = (
421+ remove_security_proxy_and_shout_at_engineer(
422+ self.dev_productseries))
423+ naked_dev_productseries.status = SeriesStatus.DEVELOPMENT
424
425 self.distribution = self.factory.makeDistribution(
426 name='youbuntu', displayname='Youbuntu', owner=self.owner)
427
428=== modified file 'lib/lp/soyuz/adapters/tests/test_packagelocation.py'
429--- lib/lp/soyuz/adapters/tests/test_packagelocation.py 2010-06-22 12:08:51 +0000
430+++ lib/lp/soyuz/adapters/tests/test_packagelocation.py 2010-07-22 14:11:16 +0000
431@@ -12,8 +12,10 @@
432 from lp.soyuz.interfaces.archive import ArchivePurpose
433 from lp.soyuz.interfaces.component import IComponentSet
434 from lp.testing import TestCaseWithFactory
435+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
436 from canonical.testing import LaunchpadZopelessLayer
437
438+
439 class TestPackageLocation(TestCaseWithFactory):
440 """Test the `PackageLocation` class."""
441 layer = LaunchpadZopelessLayer
442@@ -34,7 +36,8 @@
443 returned_location = self.factory.makeCopyArchiveLocation(
444 distribution=ubuntu, name='now-comes-the-mystery',
445 owner=self.factory.makePerson(name='mysteryman'))
446- copy_archive = returned_location.archive
447+ copy_archive = remove_security_proxy_and_shout_at_engineer(
448+ returned_location).archive
449
450 # Now use the created copy archive to test the build_package_location
451 # helper (called via getPackageLocation):
452
453=== modified file 'lib/lp/soyuz/browser/tests/archive-views.txt'
454--- lib/lp/soyuz/browser/tests/archive-views.txt 2010-05-21 10:59:09 +0000
455+++ lib/lp/soyuz/browser/tests/archive-views.txt 2010-07-22 14:11:16 +0000
456@@ -15,11 +15,14 @@
457
458 >>> from lp.registry.interfaces.distribution import (
459 ... IDistributionSet)
460+ >>> from lp.testing.factory import (
461+ ... remove_security_proxy_and_shout_at_engineer)
462 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
463 >>> copy_location = factory.makeCopyArchiveLocation(
464 ... distribution=ubuntu,
465 ... name="intrepid-security-rebuild")
466- >>> copy_archive = copy_location.archive
467+ >>> copy_archive = remove_security_proxy_and_shout_at_engineer(
468+ ... copy_location).archive
469
470 And let's create two views to compare:
471
472@@ -65,8 +68,10 @@
473 0
474
475 # Create a copy-request to Celso's PPA.
476+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
477+ ... copy_location)
478 >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
479- ... copy_location, copy_archive.owner)
480+ ... naked_copy_location, copy_archive.owner)
481
482 >>> len(copy_archive_view.package_copy_requests)
483 1
484
485=== modified file 'lib/lp/soyuz/browser/tests/test_distrosourcepackagerelease.py'
486--- lib/lp/soyuz/browser/tests/test_distrosourcepackagerelease.py 2010-07-20 12:06:36 +0000
487+++ lib/lp/soyuz/browser/tests/test_distrosourcepackagerelease.py 2010-07-22 14:11:16 +0000
488@@ -14,6 +14,7 @@
489 DistributionSourcePackageRelease)
490 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
491 from lp.testing import TestCaseWithFactory
492+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
493 from lp.testing.views import create_initialized_view
494
495
496@@ -27,7 +28,12 @@
497 # The package must be published for the page to render.
498 stp = SoyuzTestPublisher()
499 distroseries = stp.setUpDefaultDistroSeries()
500- distro = distroseries.distribution
501+ naked_distroseries = remove_security_proxy_and_shout_at_engineer(
502+ distroseries)
503+ # XXX Abel Deuring, 2010-07-21, bug 608240. This is scary. But
504+ # if we use distroseries.distribution instead,
505+ # test_spr_files_deleted() and test_spr_files_one() fail.
506+ distro = naked_distroseries.distribution
507 source_package_release = stp.getPubSource().sourcepackagerelease
508 self.dspr = DistributionSourcePackageRelease(
509 distro, source_package_release)
510
511=== modified file 'lib/lp/soyuz/browser/tests/test_sourcepackagerelease.py'
512--- lib/lp/soyuz/browser/tests/test_sourcepackagerelease.py 2010-07-20 12:06:36 +0000
513+++ lib/lp/soyuz/browser/tests/test_sourcepackagerelease.py 2010-07-22 14:11:16 +0000
514@@ -16,6 +16,7 @@
515 from canonical.testing import (
516 DatabaseFunctionalLayer, LaunchpadFunctionalLayer)
517 from lp.testing import TestCaseWithFactory
518+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
519 from lp.testing.views import create_initialized_view
520
521
522@@ -64,20 +65,23 @@
523
524 def test_highlighted_copyright_is_None(self):
525 expected = ''
526- self.source_package_release.copyright = None
527+ remove_security_proxy_and_shout_at_engineer(
528+ self.source_package_release).copyright = None
529 view = create_initialized_view(
530 self.source_package_release, '+copyright')
531 self.assertEqual(expected, view.highlighted_copyright)
532
533 def test_highlighted_copyright_no_matches(self):
534 expected = 'nothing to see and/or do.'
535- self.source_package_release.copyright = expected
536+ remove_security_proxy_and_shout_at_engineer(
537+ self.source_package_release).copyright = expected
538 view = create_initialized_view(
539 self.source_package_release, '+copyright')
540 self.assertEqual(expected, view.highlighted_copyright)
541
542 def test_highlighted_copyright_match_url(self):
543- self.source_package_release.copyright = (
544+ remove_security_proxy_and_shout_at_engineer(
545+ self.source_package_release).copyright = (
546 'Downloaded from https://upstream.dom/fnord/no/ and')
547 expected = (
548 'Downloaded from '
549@@ -88,7 +92,8 @@
550 self.assertEqual(expected, view.highlighted_copyright)
551
552 def test_highlighted_copyright_match_path(self):
553- self.source_package_release.copyright = (
554+ remove_security_proxy_and_shout_at_engineer(
555+ self.source_package_release).copyright = (
556 'See /usr/share/common-licenses/GPL')
557 expected = (
558 'See '
559@@ -98,7 +103,8 @@
560 self.assertEqual(expected, view.highlighted_copyright)
561
562 def test_highlighted_copyright_match_multiple(self):
563- self.source_package_release.copyright = (
564+ remove_security_proxy_and_shout_at_engineer(
565+ self.source_package_release).copyright = (
566 'See /usr/share/common-licenses/GPL or https://osi.org/mit')
567 expected = (
568 'See '
569
570=== modified file 'lib/lp/soyuz/doc/archive.txt'
571--- lib/lp/soyuz/doc/archive.txt 2010-07-21 09:41:48 +0000
572+++ lib/lp/soyuz/doc/archive.txt 2010-07-22 14:11:16 +0000
573@@ -1285,10 +1285,15 @@
574 The IArchive interface includes a convenience method for creating a
575 package copy request:
576
577+ >>> from lp.testing.factory import (
578+ ... remove_security_proxy_and_shout_at_engineer)
579 >>> requestor = factory.makePerson(name='me-copy')
580 >>> copy_target = factory.makeCopyArchiveLocation(
581 ... distribution=ubuntu, name='my-copy-archive', owner=requestor)
582- >>> pcr = ubuntu.main_archive.requestPackageCopy(copy_target, requestor)
583+ >>> naked_copy_target = remove_security_proxy_and_shout_at_engineer(
584+ ... copy_target)
585+ >>> pcr = ubuntu.main_archive.requestPackageCopy(
586+ ... naked_copy_target, requestor)
587 >>> print pcr
588 Package copy request
589 source = primary/hoary/-/RELEASE
590@@ -1301,7 +1306,7 @@
591 The requestPackageCopy method can also take an optional suite name:
592
593 >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
594- ... copy_target, requestor, suite="hoary-updates");
595+ ... naked_copy_target, requestor, suite="hoary-updates");
596 >>> print package_copy_request
597 Package copy request
598 source = primary/hoary/-/UPDATES
599@@ -1412,9 +1417,9 @@
600
601 COPY archives use a URL format of <distro-name>-<archive-name>:
602
603- >>> print copy_target.archive.is_copy
604+ >>> print naked_copy_target.archive.is_copy
605 True
606- >>> print copy_target.archive.archive_url
607+ >>> print naked_copy_target.archive.archive_url
608 http://rebuild-test.internal/ubuntu-my-copy-archive/ubuntu
609
610 If the archive is private, the url may be different as private PPAs
611
612=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt'
613--- lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2010-01-12 08:24:36 +0000
614+++ lib/lp/soyuz/stories/soyuz/xx-distribution-archives.txt 2010-07-22 14:11:16 +0000
615@@ -6,6 +6,8 @@
616 >>> from canonical.launchpad.interfaces import (
617 ... IDistributionSet)
618 >>> from lp.registry.interfaces.person import IPersonSet
619+ >>> from lp.testing.factory import (
620+ ... remove_security_proxy_and_shout_at_engineer)
621 >>> login('foo.bar@canonical.com')
622 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
623
624@@ -13,18 +15,21 @@
625 >>> copy_location = factory.makeCopyArchiveLocation(
626 ... distribution=ubuntu, owner=joe,
627 ... name="intrepid-security-rebuild")
628- >>> copy_archive = copy_location.archive
629+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
630+ ... copy_location)
631+ >>> copy_archive = naked_copy_location.archive
632 >>> copy_archive.enabled
633 True
634
635 >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
636- ... copy_location, copy_archive.owner)
637+ ... naked_copy_location, copy_archive.owner)
638
639 >>> nopriv = getUtility(IPersonSet).getByName('no-priv')
640 >>> disabled_location = factory.makeCopyArchiveLocation(
641 ... distribution=ubuntu, owner=nopriv,
642 ... name="disabled-security-rebuild", enabled=False)
643- >>> disabled_archive = disabled_location.archive
644+ >>> disabled_archive = remove_security_proxy_and_shout_at_engineer(
645+ ... disabled_location).archive
646 >>> disabled_archive.enabled
647 False
648
649@@ -119,12 +124,14 @@
650 >>> copy_location = factory.makeCopyArchiveLocation(
651 ... distribution=ubuntu,
652 ... name="intrepid-private-security-rebuild")
653- >>> copy_archive = copy_location.archive
654+ >>> naked_copy_location = remove_security_proxy_and_shout_at_engineer(
655+ ... copy_location)
656+ >>> copy_archive = naked_copy_location.archive
657 >>> copy_archive.buildd_secret = 'really secret'
658 >>> copy_archive.private = True
659 >>> copy_archive.owner.displayname = "Harry Potter"
660 >>> package_copy_request = ubuntu.main_archive.requestPackageCopy(
661- ... copy_location, copy_archive.owner)
662+ ... naked_copy_location, copy_archive.owner)
663 >>> pub_src = stp.getPubSource(
664 ... archive=copy_archive, architecturehintlist='any')
665 >>> pub_bins = stp.getPubBinaries(pub_source=pub_src)
666
667=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
668--- lib/lp/soyuz/tests/test_publishing.py 2010-07-21 14:14:54 +0000
669+++ lib/lp/soyuz/tests/test_publishing.py 2010-07-22 14:11:16 +0000
670@@ -44,7 +44,8 @@
671 from lp.soyuz.interfaces.queue import PackageUploadStatus
672 from canonical.launchpad.scripts import FakeLogger
673 from lp.testing import TestCaseWithFactory
674-from lp.testing.factory import LaunchpadObjectFactory
675+from lp.testing.factory import (
676+ LaunchpadObjectFactory, remove_security_proxy_and_shout_at_engineer)
677 from lp.testing.fakemethod import FakeMethod
678
679
680@@ -146,7 +147,10 @@
681 PackageUploadStatus.DONE: 'setDone',
682 PackageUploadStatus.ACCEPTED: 'setAccepted',
683 }
684- method = getattr(package_upload, status_to_method[upload_status])
685+ naked_package_upload = remove_security_proxy_and_shout_at_engineer(
686+ package_upload)
687+ method = getattr(
688+ naked_package_upload, status_to_method[upload_status])
689 method()
690
691 return package_upload
692@@ -222,7 +226,9 @@
693 changes_file_name=changes_file_name,
694 changes_file_content=changes_file_content,
695 upload_status=upload_status)
696- package_upload.addSource(spr)
697+ naked_package_upload = remove_security_proxy_and_shout_at_engineer(
698+ package_upload)
699+ naked_package_upload.addSource(spr)
700
701 if filename is None:
702 filename = "%s_%s.dsc" % (sourcename, version)
703
704=== modified file 'lib/lp/testing/factory.py'
705--- lib/lp/testing/factory.py 2010-07-21 14:41:26 +0000
706+++ lib/lp/testing/factory.py 2010-07-22 14:11:16 +0000
707@@ -13,8 +13,10 @@
708 __metaclass__ = type
709 __all__ = [
710 'GPGSigningContext',
711+ 'is_security_proxied_or_harmless',
712 'LaunchpadObjectFactory',
713 'ObjectFactory',
714+ 'remove_security_proxy_and_shout_at_engineer',
715 ]
716
717 from contextlib import nested
718@@ -25,18 +27,22 @@
719 from email.mime.text import MIMEText
720 from email.mime.multipart import MIMEMultipart
721 from itertools import count
722+from operator import isSequenceType
723 import os.path
724 from random import randint
725 from StringIO import StringIO
726+import sys
727 from textwrap import dedent
728 from threading import local
729+from types import InstanceType
730
731 import pytz
732
733 from twisted.python.util import mergeFunctionMetadata
734
735 from zope.component import ComponentLookupError, getUtility
736-from zope.security.proxy import removeSecurityProxy
737+from zope.security.proxy import (
738+ builtin_isinstance, Proxy, ProxyFactory, removeSecurityProxy)
739
740 from canonical.autodecorate import AutoDecorate
741 from canonical.config import config
742@@ -325,7 +331,7 @@
743 branch_id, rcstype, url, cvs_root, cvs_module)
744
745
746-class LaunchpadObjectFactory(ObjectFactory):
747+class BareLaunchpadObjectFactory(ObjectFactory):
748 """Factory methods for creating Launchpad objects.
749
750 All the factory methods should be callable with no parameters.
751@@ -356,7 +362,7 @@
752
753 location = PackageLocation(copy_archive, distribution, distroseries,
754 pocket)
755- return location
756+ return ProxyFactory(location)
757
758 def makeAccount(self, displayname, email=None, password=None,
759 status=AccountStatus.ACTIVE,
760@@ -744,8 +750,8 @@
761 # We don't want to login() as the person used to create the product,
762 # so we remove the security proxy before creating the series.
763 naked_product = removeSecurityProxy(product)
764- return naked_product.newSeries(owner=owner, name=name,
765- summary=summary)
766+ return ProxyFactory(
767+ naked_product.newSeries(owner=owner, name=name, summary=summary))
768
769 def makeProject(self, name=None, displayname=None, title=None,
770 homepageurl=None, summary=None, owner=None,
771@@ -1034,7 +1040,7 @@
772 CodeReviewNotificationLevel.NOEMAIL, subscribed_by)
773
774 def makeDiff(self, diff_text=DIFF):
775- return Diff.fromFile(StringIO(diff_text), len(diff_text))
776+ return ProxyFactory(Diff.fromFile(StringIO(diff_text), len(diff_text)))
777
778 def makePreviewDiff(self, conflicts=u''):
779 diff = self.makeDiff()
780@@ -1671,7 +1677,7 @@
781 description=self.getUniqueString(),
782 parent_series=parent_series, owner=distribution.owner)
783 series.status = status
784- return series
785+ return ProxyFactory(series)
786
787 # Most people think of distro releases as distro series.
788 makeDistroSeries = makeDistroRelease
789@@ -1780,7 +1786,7 @@
790
791 def makeRecipeText(self, *branches):
792 if len(branches) == 0:
793- branches = (self.makeAnyBranch(),)
794+ branches = (self.makeAnyBranch(), )
795 base_branch = branches[0]
796 other_branches = branches[1:]
797 text = MINIMAL_RECIPE_TEXT % base_branch.bzr_identity
798@@ -1943,7 +1949,7 @@
799 productseries = self.makeProductSeries(owner=owner)
800 # Make it use Translations, otherwise there's little point
801 # to us creating a template for it.
802- productseries.product.official_rosetta = True
803+ removeSecurityProxy(productseries).product.official_rosetta = True
804 templateset = getUtility(IPOTemplateSet)
805 subset = templateset.getSubset(
806 distroseries, sourcepackagename, productseries)
807@@ -2718,3 +2724,73 @@
808 new_uuid = getUtility(ITemporaryStorageManager).new(blob, expires)
809
810 return getUtility(ITemporaryStorageManager).fetch(new_uuid)
811+
812+
813+# Some factory methods return simple Python types. We don't add
814+# security wrappers for them, as well as for objects created by
815+# other Python libraries.
816+unwrapped_types = (
817+ DSCFile, InstanceType, Message, datetime, int, str, unicode)
818+
819+def is_security_proxied_or_harmless(obj):
820+ """Check that the given object is security wrapped or a harmless object."""
821+ if obj is None:
822+ return True
823+ if builtin_isinstance(obj, Proxy):
824+ return True
825+ if type(obj) in unwrapped_types:
826+ return True
827+ if isSequenceType(obj):
828+ for element in obj:
829+ if not is_security_proxied_or_harmless(element):
830+ return False
831+ return True
832+ return False
833+
834+
835+class LaunchpadObjectFactory:
836+ """A wrapper around `BareLaunchpadObjectFactory`.
837+
838+ Ensure that each object created by a `BareLaunchpadObjectFactory` method
839+ is either of a simple Python type or is security proxied.
840+
841+ A warning message is printed to stderr if a factory method creates
842+ an object without a security proxy.
843+
844+ Whereever you see such a warning: fix it!
845+ """
846+ def __init__(self):
847+ self._factory = BareLaunchpadObjectFactory()
848+
849+ def __getattr__(self, name):
850+ attr = getattr(self._factory, name)
851+ if callable(attr):
852+
853+ def guarded_method(*args, **kw):
854+ result = attr(*args, **kw)
855+ if not is_security_proxied_or_harmless(result):
856+ message = (
857+ "PLEASE FIX: LaunchpadObjectFactory.%s returns an "
858+ "unproxied object." % name)
859+ print >>sys.stderr, message
860+ return result
861+ return guarded_method
862+ else:
863+ return attr
864+
865+
866+def remove_security_proxy_and_shout_at_engineer(obj):
867+ """Remove an object's security proxy and print a warning.
868+
869+ A number of LaunchpadObjectFactory methods returned objects without
870+ a security proxy. This is now no longer possible, but a number of
871+ tests rely on unrestricted access to object attributes.
872+
873+ This function should only be used in legacy tests which fail because
874+ they expect unproxied objects.
875+ """
876+ print >>sys.stderr, (
877+ "\nWarning: called removeSecurityProxy() for %r without a check if "
878+ "this reasonable. Look for a call of "
879+ "remove_security_proxy_and_shout_at_engineer(some_object)." % obj)
880+ return removeSecurityProxy(obj)
881
882=== modified file 'lib/lp/testing/tests/test_factory.py'
883--- lib/lp/testing/tests/test_factory.py 2010-07-17 18:40:02 +0000
884+++ lib/lp/testing/tests/test_factory.py 2010-07-22 14:11:16 +0000
885@@ -8,11 +8,13 @@
886 import unittest
887
888 from zope.component import getUtility
889+from zope.security.proxy import removeSecurityProxy
890
891 from canonical.launchpad.webapp.interfaces import ILaunchBag
892 from canonical.testing.layers import DatabaseFunctionalLayer
893 from lp.code.enums import CodeImportReviewStatus
894 from lp.testing import TestCaseWithFactory
895+from lp.testing.factory import is_security_proxied_or_harmless
896
897
898 class TestFactory(TestCaseWithFactory):
899@@ -39,6 +41,54 @@
900 self.assertIsNot(None, person)
901 self.assertEqual(person, current_person)
902
903+ def test_is_security_proxied_or_harmless__none(self):
904+ # is_security_proxied_or_harmless() considers the None object
905+ # to be a harmless object.
906+ self.assertTrue(is_security_proxied_or_harmless(None))
907+
908+ def test_is_security_proxied_or_harmless__int(self):
909+ # is_security_proxied_or_harmless() considers integers
910+ # to be harmless.
911+ self.assertTrue(is_security_proxied_or_harmless(1))
912+
913+ def test_is_security_proxied_or_harmless__string(self):
914+ # is_security_proxied_or_harmless() considers strings
915+ # to be harmless.
916+ self.assertTrue(is_security_proxied_or_harmless('abc'))
917+
918+ def test_is_security_proxied_or_harmless__unicode(self):
919+ # is_security_proxied_or_harmless() considers unicode objects
920+ # to be harmless.
921+ self.assertTrue(is_security_proxied_or_harmless(u'abc'))
922+
923+ def test_is_security_proxied_or_harmless__proxied_object(self):
924+ # is_security_proxied_or_harmless() treats security proxied
925+ # objects as harmless.
926+ proxied_person = self.factory.makePerson()
927+ self.assertTrue(is_security_proxied_or_harmless(proxied_person))
928+
929+ def test_is_security_proxied_or_harmless__unproxied_object(self):
930+ # is_security_proxied_or_harmless() treats security proxied
931+ # objects as harmless.
932+ unproxied_person = removeSecurityProxy(self.factory.makePerson())
933+ self.assertFalse(is_security_proxied_or_harmless(unproxied_person))
934+
935+ def test_is_security_proxied_or_harmless__sequence_harmless_content(self):
936+ # is_security_proxied_or_harmless() checks all elements
937+ # of a sequence. If all elements are harmless, so is the
938+ # sequence.
939+ proxied_person = self.factory.makePerson()
940+ self.assertTrue(
941+ is_security_proxied_or_harmless([1, '2', proxied_person]))
942+
943+ def test_is_security_proxied_or_harmless__sequence_harmful_content(self):
944+ # is_security_proxied_or_harmless() checks all elements
945+ # of a sequence. If at least one element is harmful, so is the
946+ # sequence.
947+ unproxied_person = removeSecurityProxy(self.factory.makePerson())
948+ self.assertFalse(
949+ is_security_proxied_or_harmless([1, '2', unproxied_person]))
950+
951
952 def test_suite():
953 return unittest.TestLoader().loadTestsFromName(__name__)
954
955=== modified file 'lib/lp/translations/browser/tests/test_breadcrumbs.py'
956--- lib/lp/translations/browser/tests/test_breadcrumbs.py 2010-07-19 15:31:57 +0000
957+++ lib/lp/translations/browser/tests/test_breadcrumbs.py 2010-07-22 14:11:16 +0000
958@@ -9,6 +9,7 @@
959
960 from lp.services.worlddata.interfaces.language import ILanguageSet
961 from lp.testing.breadcrumbs import BaseBreadcrumbTestCase
962+from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
963 from lp.translations.interfaces.distroserieslanguage import (
964 IDistroSeriesLanguageSet)
965 from lp.translations.interfaces.productserieslanguage import (
966@@ -109,7 +110,8 @@
967 name='crumb-tester', displayname="Crumb Tester")
968 series = self.factory.makeDistroRelease(
969 name="test", version="1.0", distribution=distribution)
970- series.hide_all_translations = False
971+ naked_series = remove_security_proxy_and_shout_at_engineer(series)
972+ naked_series.hide_all_translations = False
973 serieslanguage = getUtility(IDistroSeriesLanguageSet).getDummy(
974 series, self.language)
975
976
977=== modified file 'lib/lp/translations/doc/translations-export-to-branch.txt'
978--- lib/lp/translations/doc/translations-export-to-branch.txt 2010-06-16 07:22:57 +0000
979+++ lib/lp/translations/doc/translations-export-to-branch.txt 2010-07-22 14:11:16 +0000
980@@ -220,8 +220,12 @@
981 >>> from email import message_from_string
982 >>> from lp.services.mail import stub
983 >>> from lp.codehosting.vfs import get_rw_server
984+ >>> from lp.testing.factory import (
985+ ... remove_security_proxy_and_shout_at_engineer)
986 >>> productseries = factory.makeProductSeries()
987- >>> productseries.translations_branch = factory.makeBranch()
988+ >>> naked_productseries = remove_security_proxy_and_shout_at_engineer(
989+ ... productseries)
990+ >>> naked_productseries.translations_branch = factory.makeBranch()
991 >>> template = factory.makePOTemplate(productseries=productseries)
992 >>> potmsgset = factory.makePOTMsgSet(template)
993 >>> pofile = removeSecurityProxy(
994
995=== modified file 'lib/lp/translations/stories/buildfarm/xx-build-summary.txt'
996--- lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2010-03-16 11:09:46 +0000
997+++ lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2010-07-22 14:11:16 +0000
998@@ -14,6 +14,8 @@
999 ... ILibraryFileAliasSet)
1000 >>> from canonical.launchpad.scripts.logger import QuietFakeLogger
1001 >>> from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
1002+ >>> from lp.testing.factory import (
1003+ ... remove_security_proxy_and_shout_at_engineer)
1004 >>> from lp.testing.fakemethod import FakeMethod
1005 >>> from lp.translations.interfaces.translations import (
1006 ... TranslationsBranchImportMode)
1007@@ -29,12 +31,15 @@
1008
1009 >>> productseries = factory.makeProductSeries(owner=owner)
1010 >>> product = productseries.product
1011- >>> product.official_rosetta = True
1012+ >>> naked_product = remove_security_proxy_and_shout_at_engineer(product)
1013+ >>> naked_product.official_rosetta = True
1014 >>> branch = factory.makeProductBranch(product=product, owner=owner)
1015 >>> branch_url = branch.unique_name
1016
1017- >>> productseries.branch = factory.makeBranch()
1018- >>> productseries.translations_autoimport_mode = (
1019+ >>> naked_productseries = remove_security_proxy_and_shout_at_engineer(
1020+ ... productseries)
1021+ >>> naked_productseries.branch = factory.makeBranch()
1022+ >>> naked_productseries.translations_autoimport_mode = (
1023 ... TranslationsBranchImportMode.IMPORT_TEMPLATES)
1024 >>> specific_job = factory.makeTranslationTemplatesBuildJob(branch=branch)
1025 >>> buildqueue = getUtility(IBuildQueueSet).getByJob(specific_job.job)