Merge lp:~james-w/launchpad/no-more-sampledata-0 into lp:launchpad

Proposed by James Westby
Status: Merged
Approved by: Jonathan Lange
Approved revision: no longer in the source branch.
Merged at revision: 11293
Proposed branch: lp:~james-w/launchpad/no-more-sampledata-0
Merge into: lp:launchpad
Diff against target: 1358 lines (+769/-248)
10 files modified
lib/lp/soyuz/tests/ppa.py (+13/-7)
lib/lp/soyuz/tests/soyuz.py (+15/-10)
lib/lp/soyuz/tests/soyuzbuilddhelpers.py (+4/-3)
lib/lp/soyuz/tests/test_archive.py (+135/-155)
lib/lp/testing/__init__.py (+3/-8)
lib/lp/testing/factory.py (+84/-57)
lib/lp/testing/matchers.py (+135/-0)
lib/lp/testing/sampledata.py (+38/-0)
lib/lp/testing/tests/test_factory.py (+171/-8)
lib/lp/testing/tests/test_matchers.py (+171/-0)
To merge this branch: bzr merge lp:~james-w/launchpad/no-more-sampledata-0
Reviewer Review Type Date Requested Status
Jonathan Lange (community) Approve
Review via email: mp+31470@code.launchpad.net

Description of the change

Hi,

This changes a bunch of soyuz tests to not use the sampledata.

It goes a bit further than that in that it restructures them to
have less setup and to create the things they need using the
factory rather than SoyuzTestPublisher.

In addition I moved some other code that is too deeply buried
right now in to lp.testing.sampledata, and extended the factory
with some new methods to satisfy the needs of the changed code.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :
Download full text (30.3 KiB)

On Sun, Aug 1, 2010 at 12:06 AM, James Westby <email address hidden> wrote:
> James Westby has proposed merging lp:~james-w/launchpad/no-more-sampledata-0 into lp:launchpad/devel.
>
> Requested reviews:
>  Launchpad code reviewers (launchpad-reviewers)
>
>
> Hi,
>
> This changes a bunch of soyuz tests to not use the sampledata.
>

Woot.

> It goes a bit further than that in that it restructures them to
> have less setup and to create the things they need using the
> factory rather than SoyuzTestPublisher.
>
> In addition I moved some other code that is too deeply buried
> right now in to lp.testing.sampledata, and extended the factory
> with some new methods to satisfy the needs of the changed code.
>
> Thanks,
>

Thank you.

The review below mostly picks up on some naming standard glitches and
points out some things that could be improved in the soyuz tests
(rather than in your changes). However, I've also got a couple of
questions about your changes and would very much appreciate hearing
back from you.

I also feel a little guilty about making so many petty comments when
you've done such a helpful thing. Please do not feel obliged to act on
all of my suggestions.

jml

> === modified file 'lib/lp/soyuz/tests/ppa.py'
> --- lib/lp/soyuz/tests/ppa.py   2010-03-11 16:48:37 +0000
> +++ lib/lp/soyuz/tests/ppa.py   2010-07-31 23:06:48 +0000
> @@ -25,6 +25,10 @@
>  from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
>  from lp.soyuz.interfaces.publishing import (
>     PackagePublishingPriority, PackagePublishingStatus)
> +from lp.testing.sampledata import (
> +    HOARY_DISTROSERIES_NAME, I386_ARCHITECTURE_NAME, MAIN_COMPONENT_NAME,
> +    MOZILLA_FIREFOX_SOURCEPACKAGENAME, MOZILLA_FIREFOX_SOURCEPACKAGEVERSION,
> +    NAME16_PERSON_NAME, UBUNTU_TEAM_NAME)
>

I'm very glad you've started putting things in the sampledata module.

Would it be possible to change these names to clarify the intent
behind their use?

For example, NAME16_PERSON_NAME tells me nothing about the person
object, and when I see it in a test, I don't know why name16 was
chosen instead of name15. UBUNTU_TEAM_MEMBER_NAME might be better.
Likewise, it would be good to have intent-revealing names for the
FIREFOX constants and the HOARY constants.

> === modified file 'lib/lp/soyuz/tests/soyuz.py'
> --- lib/lp/soyuz/tests/soyuz.py 2010-02-08 11:40:06 +0000
> +++ lib/lp/soyuz/tests/soyuz.py 2010-07-31 23:06:48 +0000
> @@ -27,14 +27,19 @@
>  from lp.soyuz.model.publishing import (
>     SourcePackagePublishingHistory,
>     BinaryPackagePublishingHistory)
> +from lp.testing.sampledata import (
> +    CHROOT_LFA, CPROV_NAME, I386_ARCHITECTURE_NAME, LAUNCHPAD_DBUSER_NAME,
> +    UBUNTU_DISTRIBUTION_NAME, WARTY_DISTROSERIES_NAME,
> +    WARTY_UPDATES_SUITE_NAME)
>

Ditto CPROV, LAUNCHPAD_DBUSER_NAME and WARTY_*

> === modified file 'lib/lp/soyuz/tests/test_archive.py'
> --- lib/lp/soyuz/tests/test_archive.py  2010-07-21 07:45:50 +0000
> +++ lib/lp/soyuz/tests/test_archive.py  2010-07-31 23:06:48 +0000
...
> @@ -42,118 +41,110 @@
>
>  class TestGetPublicationsInArchive(TestCaseWithFactory):
>
> -    layer = LaunchpadZopelessLayer
> -
> -    def setUp(self):
> -    ...

Revision history for this message
Jonathan Lange (jml) wrote :

As per my comments via email.

review: Needs Fixing
Revision history for this message
James Westby (james-w) wrote :

> The review below mostly picks up on some naming standard glitches and
> points out some things that could be improved in the soyuz tests
> (rather than in your changes). However, I've also got a couple of
> questions about your changes and would very much appreciate hearing
> back from you.
>
> I also feel a little guilty about making so many petty comments when
> you've done such a helpful thing. Please do not feel obliged to act on
> all of my suggestions.

Thanks for the review. The intent is to improve the understandability
of the tests, so your suggestions are helpful.

> > === modified file 'lib/lp/soyuz/tests/ppa.py'
> > --- lib/lp/soyuz/tests/ppa.py   2010-03-11 16:48:37 +0000
> > +++ lib/lp/soyuz/tests/ppa.py   2010-07-31 23:06:48 +0000
> > @@ -25,6 +25,10 @@
> >  from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
> >  from lp.soyuz.interfaces.publishing import (
> >     PackagePublishingPriority, PackagePublishingStatus)
> > +from lp.testing.sampledata import (
> > +    HOARY_DISTROSERIES_NAME, I386_ARCHITECTURE_NAME, MAIN_COMPONENT_NAME,
> > +    MOZILLA_FIREFOX_SOURCEPACKAGENAME,
> MOZILLA_FIREFOX_SOURCEPACKAGEVERSION,
> > +    NAME16_PERSON_NAME, UBUNTU_TEAM_NAME)
> >
>
> I'm very glad you've started putting things in the sampledata module.
>
> Would it be possible to change these names to clarify the intent
> behind their use?
>
> For example, NAME16_PERSON_NAME tells me nothing about the person
> object, and when I see it in a test, I don't know why name16 was
> chosen instead of name15. UBUNTU_TEAM_MEMBER_NAME might be better.
> Likewise, it would be good to have intent-revealing names for the
> FIREFOX constants and the HOARY constants.

I can do that, but it will require some research. It's one of the
problems with sampledata that I don't know what the intent is.

> My comment about the other error message applies here. I think it can
> be dropped. (If archives have unhelpful __repr__ implementations, we
> should fix that rather than working around it all the time in tests).

They have the default repr, should we change that?

> Hmm. These assertions look very much like the ones previous. Is there
> a domain-specific assertion method or Matcher to be had here?

Probably, I'll take a look. I think there's only two uses, so it hadn't
hit my refactoring threshold yet.

> I think this one needs a comment. What's an LFA?

LibraryFileAlias, I thought it was standard parlance, should I expand the
variable name instead?

Thanks,

James

Revision history for this message
Jonathan Lange (jml) wrote :

On Mon, Aug 2, 2010 at 2:25 PM, James Westby <email address hidden> wrote:
...
>> > === modified file 'lib/lp/soyuz/tests/ppa.py'
>> > --- lib/lp/soyuz/tests/ppa.py   2010-03-11 16:48:37 +0000
>> > +++ lib/lp/soyuz/tests/ppa.py   2010-07-31 23:06:48 +0000
>> > @@ -25,6 +25,10 @@
>> >  from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
>> >  from lp.soyuz.interfaces.publishing import (
>> >     PackagePublishingPriority, PackagePublishingStatus)
>> > +from lp.testing.sampledata import (
>> > +    HOARY_DISTROSERIES_NAME, I386_ARCHITECTURE_NAME, MAIN_COMPONENT_NAME,
>> > +    MOZILLA_FIREFOX_SOURCEPACKAGENAME,
>> MOZILLA_FIREFOX_SOURCEPACKAGEVERSION,
>> > +    NAME16_PERSON_NAME, UBUNTU_TEAM_NAME)
>> >
>>
>> I'm very glad you've started putting things in the sampledata module.
>>
>> Would it be possible to change these names to clarify the intent
>> behind their use?
>>
>> For example, NAME16_PERSON_NAME tells me nothing about the person
>> object, and when I see it in a test, I don't know why name16 was
>> chosen instead of name15. UBUNTU_TEAM_MEMBER_NAME might be better.
>> Likewise, it would be good to have intent-revealing names for the
>> FIREFOX constants and the HOARY constants.
>
> I can do that, but it will require some research. It's one of the
> problems with sampledata that I don't know what the intent is.
>

At the very least make the UBUNTU_TEAM_MEMBER_NAME change and add some comments.

I don't want to make you spend a whole heap of time figuring out why
all of this stuff gets used. However, I'm also a little worried that
the trend will continue. Perhaps we could work a little to avoid the
risk by adding some comments or something. I don't know.

>> My comment about the other error message applies here. I think it can
>> be dropped. (If archives have unhelpful __repr__ implementations, we
>> should fix that rather than working around it all the time in tests).
>
> They have the default repr, should we change that?
>

Don't bother. Someone else can when it comes time to actually debug.

>> Hmm. These assertions look very much like the ones previous. Is there
>> a domain-specific assertion method or Matcher to be had here?
>
> Probably, I'll take a look. I think there's only two uses, so it hadn't
> hit my refactoring threshold yet.
>

Yeah, maybe it's not needed.

>> I think this one needs a comment. What's an LFA?
>
> LibraryFileAlias, I thought it was standard parlance, should I expand the
> variable name instead?
>

Hmm, maybe it is. I don't do much with the librarian.

I have no strong opinion about the rename. Follow your heart.

cheers,
jml

Revision history for this message
James Westby (james-w) wrote :

Hi,

I have made all the requested changes.

I went a little further than necessary and created some matchers
rather than new assertion methods.

Thanks,

James

Revision history for this message
James Westby (james-w) wrote :

I tried to rename the sampledata variables as best I could, but for things
like "hoary", it just means "one bag of stuff as opposed to 'warty' which
is a different bag of stuff."

Thanks,

James

Revision history for this message
Robert Collins (lifeless) wrote :

Something that stood out to me, and perhaps jml's review mentions this
is that your new factory methods don't seem to have tests?

-Rob

Revision history for this message
James Westby (james-w) wrote :

On Mon, 02 Aug 2010 20:01:40 -0000, Robert Collins <email address hidden> wrote:
> Something that stood out to me, and perhaps jml's review mentions this
> is that your new factory methods don't seem to have tests?

It did, and they do now.

Thanks,

James

Revision history for this message
Jonathan Lange (jml) wrote :

Awesome. Thanks so much.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/tests/ppa.py'
2--- lib/lp/soyuz/tests/ppa.py 2010-03-11 16:48:37 +0000
3+++ lib/lp/soyuz/tests/ppa.py 2010-08-04 00:47:45 +0000
4@@ -25,6 +25,10 @@
5 from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
6 from lp.soyuz.interfaces.publishing import (
7 PackagePublishingPriority, PackagePublishingStatus)
8+from lp.testing.sampledata import (
9+ HOARY_DISTROSERIES_NAME, I386_ARCHITECTURE_NAME, MAIN_COMPONENT_NAME,
10+ UBUNTU_DEVELOPER_ADMIN_NAME, UBUNTU_UPLOAD_TEAM_NAME,
11+ WARTY_ONLY_SOURCEPACKAGENAME, WARTY_ONLY_SOURCEPACKAGEVERSION)
12
13
14 def publishToTeamPPA(team_name=None, distroseries_name=None,
15@@ -40,15 +44,16 @@
16 The team PPA must already be created.
17 """
18 if team_name is None:
19- team_name = "ubuntu-team"
20+ team_name = UBUNTU_UPLOAD_TEAM_NAME
21 if team_member_name is None:
22- team_member_name = "name16"
23+ team_member_name = UBUNTU_DEVELOPER_ADMIN_NAME
24 team = getUtility(IPersonSet).getByName(team_name)
25 _publishToPPA(
26 team.archive, team_member_name, distroseries_name,
27 sourcepackage_name, sourcepackage_version, distribution_name,
28 binarypackage_version, publishing_status, arch)
29
30+
31 def publishToPPA(person_name, distroseries_name=None, sourcepackage_name=None,
32 sourcepackage_version=None, distribution_name=None,
33 binarypackage_version=None, publishing_status=None,
34@@ -59,6 +64,7 @@
35 distribution_name, binarypackage_version, publishing_status,
36 arch)
37
38+
39 def _publishToPPA(archive, person_name, distroseries_name, sourcepackage_name,
40 sourcepackage_version, distribution_name,
41 binarypackage_version, publishing_status, arch):
42@@ -67,15 +73,15 @@
43 else:
44 distribution = getUtility(IDistributionSet)[distribution_name]
45 if distroseries_name is None:
46- distroseries_name = "hoary"
47+ distroseries_name = HOARY_DISTROSERIES_NAME
48 if sourcepackage_name is None:
49- sourcepackage_name = "mozilla-firefox"
50+ sourcepackage_name = WARTY_ONLY_SOURCEPACKAGENAME
51 if sourcepackage_version is None:
52- sourcepackage_version = "0.9"
53+ sourcepackage_version = WARTY_ONLY_SOURCEPACKAGEVERSION
54 if publishing_status is None:
55 publishing_status = PackagePublishingStatus.PENDING
56 if arch is None:
57- arch = "i386"
58+ arch = I386_ARCHITECTURE_NAME
59
60 sourcepackagename = getUtility(ISourcePackageNameSet)[sourcepackage_name]
61 distroseries = distribution[distroseries_name]
62@@ -88,7 +94,7 @@
63 # XXX: kiko 2007-10-25: oy, what a hack. I need to test with cprov
64 # and he doesn't have a signing key in the database
65 sourcepackagerelease.dscsigningkey = person.gpg_keys[0]
66- main_component = getUtility(IComponentSet)['main']
67+ main_component = getUtility(IComponentSet)[MAIN_COMPONENT_NAME]
68 SourcePackagePublishingHistory(
69 distroseries=distroseries,
70 sourcepackagerelease=sourcepackagerelease,
71
72=== modified file 'lib/lp/soyuz/tests/soyuz.py'
73--- lib/lp/soyuz/tests/soyuz.py 2010-02-08 11:40:06 +0000
74+++ lib/lp/soyuz/tests/soyuz.py 2010-08-04 00:47:45 +0000
75@@ -27,14 +27,19 @@
76 from lp.soyuz.model.publishing import (
77 SourcePackagePublishingHistory,
78 BinaryPackagePublishingHistory)
79+from lp.testing.sampledata import (
80+ BUILDD_ADMIN_USERNAME, CHROOT_LIBRARYFILEALIAS, I386_ARCHITECTURE_NAME,
81+ LAUNCHPAD_DBUSER_NAME, UBUNTU_DISTRIBUTION_NAME, WARTY_DISTROSERIES_NAME,
82+ WARTY_UPDATES_SUITE_NAME)
83
84
85 class SoyuzTestHelper:
86 """Helper class to support easier tests in Soyuz component."""
87
88 def __init__(self):
89- self.ubuntu = getUtility(IDistributionSet)['ubuntu']
90- self.cprov_archive = getUtility(IPersonSet).getByName('cprov').archive
91+ self.ubuntu = getUtility(IDistributionSet)[UBUNTU_DISTRIBUTION_NAME]
92+ self.cprov_archive = getUtility(
93+ IPersonSet).getByName(BUILDD_ADMIN_USERNAME).archive
94
95 @property
96 def sample_publishing_data(self):
97@@ -142,12 +147,13 @@
98 Store the `FakePackager` object used in the test uploads as `packager`
99 so the tests can reuse it if necessary.
100 """
101- self.layer.alterConnection(dbuser='launchpad')
102+ self.layer.alterConnection(dbuser=LAUNCHPAD_DBUSER_NAME)
103
104- fake_chroot = LibraryFileAlias.get(1)
105- ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
106- warty = ubuntu.getSeries('warty')
107- warty['i386'].addOrUpdateChroot(fake_chroot)
108+ fake_chroot = LibraryFileAlias.get(CHROOT_LIBRARYFILEALIAS)
109+ ubuntu = getUtility(IDistributionSet).getByName(
110+ UBUNTU_DISTRIBUTION_NAME)
111+ warty = ubuntu.getSeries(WARTY_DISTROSERIES_NAME)
112+ warty[I386_ARCHITECTURE_NAME].addOrUpdateChroot(fake_chroot)
113
114 self.layer.txn.commit()
115
116@@ -176,13 +182,13 @@
117 'zeca', '1.0', 'foo.bar@canonical.com-passwordless.sec')
118 packager.buildUpstream()
119 packager.buildSource()
120- packager.uploadSourceVersion('1.0-1', suite="warty-updates")
121+ packager.uploadSourceVersion('1.0-1', suite=WARTY_UPDATES_SUITE_NAME)
122
123 # Upload a new version of the source, so a PackageDiff can
124 # be created.
125 packager.buildVersion('1.0-2', changelog_text="cookies")
126 packager.buildSource(include_orig=False)
127- packager.uploadSourceVersion('1.0-2', suite="warty-updates")
128+ packager.uploadSourceVersion('1.0-2', suite=WARTY_UPDATES_SUITE_NAME)
129
130 # Check if there is exactly one pending PackageDiff record and
131 # It's the one we have just created.
132@@ -193,4 +199,3 @@
133 def getPendingDiffs(self):
134 """Pending `PackageDiff` available."""
135 return getUtility(IPackageDiffSet).getPendingDiffs()
136-
137
138=== modified file 'lib/lp/soyuz/tests/soyuzbuilddhelpers.py'
139--- lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-04-14 13:54:06 +0000
140+++ lib/lp/soyuz/tests/soyuzbuilddhelpers.py 2010-08-04 00:47:45 +0000
141@@ -26,6 +26,7 @@
142 updateBuilderStatus)
143 from lp.soyuz.model.binarypackagebuildbehavior import (
144 BinaryPackageBuildBehavior)
145+from lp.testing.sampledata import I386_ARCHITECTURE_NAME
146
147
148 class MockBuilder:
149@@ -85,7 +86,7 @@
150
151 The architecture tag can be customised during initialisation."""
152
153- def __init__(self, arch_tag='i386'):
154+ def __init__(self, arch_tag=I386_ARCHITECTURE_NAME):
155 self.arch_tag = arch_tag
156
157 def status(self):
158@@ -159,7 +160,7 @@
159 def getFile(self, sum):
160 if sum == "buildlog":
161 s = StringIO("This is a build log")
162- s.headers = {'content-length':19}
163+ s.headers = {'content-length': 19}
164 return s
165
166
167@@ -185,7 +186,7 @@
168 if hash in self.valid_file_hashes:
169 content = "This is a %s" % hash
170 s = StringIO(content)
171- s.headers = {'content-length':len(content)}
172+ s.headers = {'content-length': len(content)}
173 return s
174
175
176
177=== modified file 'lib/lp/soyuz/tests/test_archive.py'
178--- lib/lp/soyuz/tests/test_archive.py 2010-07-21 07:45:50 +0000
179+++ lib/lp/soyuz/tests/test_archive.py 2010-08-04 00:47:45 +0000
180@@ -3,10 +3,8 @@
181
182 """Test Archive features."""
183
184-from datetime import date, datetime, timedelta
185-import unittest
186+from datetime import date, timedelta
187
188-import pytz
189 import transaction
190
191 from zope.component import getUtility
192@@ -29,7 +27,8 @@
193 from lp.services.worlddata.interfaces.country import ICountrySet
194 from lp.soyuz.interfaces.archivearch import IArchiveArchSet
195 from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
196-from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat
197+from lp.soyuz.interfaces.binarypackagerelease import (
198+ BinaryPackageFileType, BinaryPackageFormat)
199 from lp.soyuz.interfaces.component import IComponentSet
200 from lp.soyuz.interfaces.processor import IProcessorFamilySet
201 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
202@@ -42,185 +41,167 @@
203
204 class TestGetPublicationsInArchive(TestCaseWithFactory):
205
206- layer = LaunchpadZopelessLayer
207-
208- def setUp(self):
209- """Use `SoyuzTestPublisher` to publish some sources in archives."""
210- super(TestGetPublicationsInArchive, self).setUp()
211-
212- self.distribution = getUtility(IDistributionSet)['ubuntutest']
213-
214- # Create two PPAs for gedit.
215- self.archives = {}
216- self.archives['ubuntu-main'] = self.distribution.main_archive
217- self.archives['gedit-nightly'] = self.factory.makeArchive(
218- name="gedit-nightly", distribution=self.distribution)
219- self.archives['gedit-beta'] = self.factory.makeArchive(
220- name="gedit-beta", distribution=self.distribution)
221-
222- self.publisher = SoyuzTestPublisher()
223- self.publisher.prepareBreezyAutotest()
224-
225- # Publish gedit in all three archives, but with different
226- # upload dates.
227- self.gedit_nightly_src_hist = self.publisher.getPubSource(
228- sourcename="gedit", archive=self.archives['gedit-nightly'],
229- date_uploaded=datetime(2010, 12, 1, tzinfo=pytz.UTC),
230- status=PackagePublishingStatus.PUBLISHED)
231- self.gedit_beta_src_hist = self.publisher.getPubSource(
232- sourcename="gedit", archive=self.archives['gedit-beta'],
233- date_uploaded=datetime(2010, 11, 30, tzinfo=pytz.UTC),
234- status=PackagePublishingStatus.PUBLISHED)
235- self.gedit_main_src_hist = self.publisher.getPubSource(
236- sourcename="gedit", archive=self.archives['ubuntu-main'],
237- date_uploaded=datetime(2010, 12, 30, tzinfo=pytz.UTC),
238- status=PackagePublishingStatus.PUBLISHED)
239-
240- # Save the archive utility for easy access, as well as the gedit
241- # source package name.
242- self.archive_set = getUtility(IArchiveSet)
243- spr = self.gedit_main_src_hist.sourcepackagerelease
244- self.gedit_name = spr.sourcepackagename
245-
246- def testReturnsAllPublishedPublications(self):
247+ layer = DatabaseFunctionalLayer
248+
249+ def makeArchivesForOneDistribution(self, count=3):
250+ distribution = self.factory.makeDistribution()
251+ archives = []
252+ for i in range(count):
253+ archives.append(
254+ self.factory.makeArchive(distribution=distribution))
255+ return archives
256+
257+ def makeArchivesWithPublications(self, count=3):
258+ archives = self.makeArchivesForOneDistribution(count=count)
259+ sourcepackagename = self.factory.makeSourcePackageName()
260+ for archive in archives:
261+ self.factory.makeSourcePackagePublishingHistory(
262+ sourcepackagename=sourcepackagename, archive=archive,
263+ status=PackagePublishingStatus.PUBLISHED,
264+ )
265+ return archives, sourcepackagename
266+
267+ def getPublications(self, sourcepackagename, archives, distribution):
268+ return getUtility(IArchiveSet).getPublicationsInArchives(
269+ sourcepackagename, archives, distribution=distribution)
270+
271+ def test_getPublications_returns_all_published_publications(self):
272 # Returns all currently published publications for archives
273- results = self.archive_set.getPublicationsInArchives(
274- self.gedit_name, self.archives.values(),
275- distribution=self.distribution)
276+ archives, sourcepackagename = self.makeArchivesWithPublications()
277+ results = self.getPublications(
278+ sourcepackagename, archives, archives[0].distribution)
279 num_results = results.count()
280- self.assertEquals(3, num_results, "Expected 3 publications but "
281- "got %s" % num_results)
282+ self.assertEquals(3, num_results)
283
284- def testEmptyListOfArchives(self):
285+ def test_getPublications_empty_list_of_archives(self):
286 # Passing an empty list of archives will result in an empty
287 # resultset.
288- results = self.archive_set.getPublicationsInArchives(
289- self.gedit_name, [], distribution=self.distribution)
290- self.assertEquals(0, results.count())
291-
292- def testReturnsOnlyPublicationsForGivenArchives(self):
293+ archives, sourcepackagename = self.makeArchivesWithPublications()
294+ results = self.getPublications(
295+ sourcepackagename, [], archives[0].distribution)
296+ self.assertEquals([], list(results))
297+
298+ def assertPublicationsFromArchives(self, publications, archives):
299+ self.assertEquals(len(archives), publications.count())
300+ for publication, archive in zip(publications, archives):
301+ self.assertEquals(archive, publication.archive)
302+
303+ def test_getPublications_returns_only_for_given_archives(self):
304 # Returns only publications for the specified archives
305- results = self.archive_set.getPublicationsInArchives(
306- self.gedit_name, [self.archives['gedit-beta']],
307- distribution=self.distribution)
308- num_results = results.count()
309- self.assertEquals(1, num_results, "Expected 1 publication but "
310- "got %s" % num_results)
311- self.assertEquals(self.archives['gedit-beta'],
312- results[0].archive,
313- "Expected publication from %s but was instead "
314- "from %s." % (
315- self.archives['gedit-beta'].displayname,
316- results[0].archive.displayname))
317+ archives, sourcepackagename = self.makeArchivesWithPublications()
318+ results = self.getPublications(
319+ sourcepackagename, [archives[0]], archives[0].distribution)
320+ self.assertPublicationsFromArchives(results, [archives[0]])
321
322- def testReturnsOnlyPublishedPublications(self):
323+ def test_getPublications_returns_only_published_publications(self):
324 # Publications that are not published will not be returned.
325- secure_src_hist = self.gedit_beta_src_hist
326- secure_src_hist.status = PackagePublishingStatus.PENDING
327-
328- results = self.archive_set.getPublicationsInArchives(
329- self.gedit_name, [self.archives['gedit-beta']],
330- distribution=self.distribution)
331- num_results = results.count()
332- self.assertEquals(0, num_results, "Expected 0 publication but "
333- "got %s" % num_results)
334-
335- def testPubsForSpecificDistro(self):
336+ archive = self.factory.makeArchive()
337+ sourcepackagename = self.factory.makeSourcePackageName()
338+ self.factory.makeSourcePackagePublishingHistory(
339+ archive=archive, sourcepackagename=sourcepackagename,
340+ status=PackagePublishingStatus.PENDING)
341+ results = self.getPublications(
342+ sourcepackagename, [archive], archive.distribution)
343+ self.assertEquals([], list(results))
344+
345+ def publishSourceInNewArchive(self, sourcepackagename):
346+ distribution = self.factory.makeDistribution()
347+ distroseries = self.factory.makeDistroSeries(
348+ distribution=distribution)
349+ archive = self.factory.makeArchive(distribution=distribution)
350+ self.factory.makeSourcePackagePublishingHistory(
351+ archive=archive, sourcepackagename=sourcepackagename,
352+ distroseries=distroseries,
353+ status=PackagePublishingStatus.PUBLISHED)
354+ return archive
355+
356+ def test_getPublications_for_specific_distro(self):
357 # Results can be filtered for specific distributions.
358-
359- # Add a publication in the ubuntu distribution
360- ubuntu = getUtility(IDistributionSet)['ubuntu']
361- warty = ubuntu['warty']
362- gedit_main_src_hist = self.publisher.getPubSource(
363- sourcename="gedit",
364- archive=self.archives['ubuntu-main'],
365- distroseries=warty,
366- date_uploaded=datetime(2010, 12, 30, tzinfo=pytz.UTC),
367- status=PackagePublishingStatus.PUBLISHED)
368-
369- # Only the 3 results for ubuntutest are returned when requested:
370- results = self.archive_set.getPublicationsInArchives(
371- self.gedit_name, self.archives.values(),
372- distribution=self.distribution)
373- num_results = results.count()
374- self.assertEquals(3, num_results, "Expected 3 publications but "
375- "got %s" % num_results)
376-
377- # Similarly, requesting the ubuntu publications only returns the
378- # one we created:
379- results = self.archive_set.getPublicationsInArchives(
380- self.gedit_name, self.archives.values(),
381- distribution=ubuntu)
382- num_results = results.count()
383- self.assertEquals(1, num_results, "Expected 1 publication but "
384- "got %s" % num_results)
385+ sourcepackagename = self.factory.makeSourcePackageName()
386+ archive = self.publishSourceInNewArchive(sourcepackagename)
387+ other_archive = self.publishSourceInNewArchive(sourcepackagename)
388+ # We don't get the results for other_distribution
389+ results = self.getPublications(
390+ sourcepackagename, [archive, other_archive],
391+ distribution=archive.distribution)
392+ self.assertPublicationsFromArchives(results, [archive])
393
394
395 class TestArchiveRepositorySize(TestCaseWithFactory):
396
397 layer = LaunchpadZopelessLayer
398
399- def setUp(self):
400- super(TestArchiveRepositorySize, self).setUp()
401- self.publisher = SoyuzTestPublisher()
402- self.publisher.prepareBreezyAutotest()
403- self.ppa = self.factory.makeArchive(
404- name="testing", distribution=self.publisher.ubuntutest)
405+ def publishDDEBInArchive(self, archive):
406+ """Publish an arbitrary DDEB with content in to the archive.
407+
408+ Publishes a DDEB that will take up some space in to `archive`.
409+
410+ :param archive: the IArchive to publish to.
411+ """
412+ binarypackagerelease = self.factory.makeBinaryPackageRelease(
413+ binpackageformat=BinaryPackageFormat.DDEB)
414+ self.factory.makeBinaryPackagePublishingHistory(
415+ archive=archive, binarypackagerelease=binarypackagerelease,
416+ status=PackagePublishingStatus.PUBLISHED)
417+ self.factory.makeBinaryPackageFile(
418+ binarypackagerelease=binarypackagerelease,
419+ filetype=BinaryPackageFileType.DDEB)
420+
421+ def test_empty_ppa_has_zero_binaries_size(self):
422+ # An empty PPA has no binaries so has zero binaries_size.
423+ ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
424+ self.assertEquals(0, ppa.binaries_size)
425
426 def test_binaries_size_does_not_include_ddebs_for_ppas(self):
427 # DDEBs are not computed in the PPA binaries size because
428 # they are not being published. See bug #399444.
429- self.assertEquals(0, self.ppa.binaries_size)
430- self.publisher.getPubBinaries(
431- filecontent='X', format=BinaryPackageFormat.DDEB,
432- archive=self.ppa)
433- self.assertEquals(0, self.ppa.binaries_size)
434+ ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
435+ self.publishDDEBInArchive(ppa)
436+ self.assertEquals(0, ppa.binaries_size)
437+
438+ def test_empty_primary_archive_has_zero_binaries_size(self):
439+ # PRIMARY archives have zero binaries_size when created.
440+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
441+ self.assertEquals(0, archive.binaries_size)
442
443 def test_binaries_size_includes_ddebs_for_other_archives(self):
444 # DDEBs size are computed for all archive purposes, except PPAs.
445- previous_size = self.publisher.ubuntutest.main_archive.binaries_size
446- self.publisher.getPubBinaries(
447- filecontent='X', format=BinaryPackageFormat.DDEB)
448- self.assertEquals(
449- previous_size + 1,
450- self.publisher.ubuntutest.main_archive.binaries_size)
451+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
452+ self.publishDDEBInArchive(archive)
453+ self.assertNotEquals(0, archive.binaries_size)
454
455 def test_sources_size_on_empty_archive(self):
456 # Zero is returned for an archive without sources.
457- self.assertEquals(
458- 0, self.ppa.sources_size,
459- 'Zero should be returned for an archive without sources.')
460+ archive = self.factory.makeArchive()
461+ self.assertEquals(0, archive.sources_size)
462+
463+ def publishSourceFile(self, archive, library_file):
464+ """Publish a source package with the given content to the archive.
465+
466+ :param archive: the IArchive to publish to.
467+ :param library_file: a LibraryFileAlias for the content of the
468+ source file.
469+ """
470+ sourcepackagerelease = self.factory.makeSourcePackageRelease()
471+ self.factory.makeSourcePackagePublishingHistory(
472+ archive=archive, sourcepackagerelease=sourcepackagerelease,
473+ status=PackagePublishingStatus.PUBLISHED)
474+ self.factory.makeSourcePackageReleaseFile(
475+ sourcepackagerelease=sourcepackagerelease,
476+ library_file=library_file)
477
478 def test_sources_size_does_not_count_duplicated_files(self):
479 # If there are multiple copies of the same file name/size
480 # only one will be counted.
481- pub_1 = self.publisher.getPubSource(
482- filecontent='22', version='0.5.11~ppa1', archive=self.ppa)
483-
484- pub_2 = self.publisher.getPubSource(
485- filecontent='333', version='0.5.11~ppa2', archive=self.ppa)
486-
487- self.assertEquals(5, self.ppa.sources_size)
488-
489- shared_tarball = self.publisher.addMockFile(
490- filename='foo_0.5.11.tar.gz', filecontent='1')
491-
492- # After adding a the shared tarball to the ppa1 version,
493- # the sources_size updates to reflect the change.
494- pub_1.sourcepackagerelease.addFile(shared_tarball)
495- self.assertEquals(
496- 6, self.ppa.sources_size,
497- 'The sources_size should update after a file is added.')
498-
499- # But after adding a copy of the shared tarball to the ppa2 version,
500- # the sources_size is unchanged.
501- shared_tarball_copy = self.publisher.addMockFile(
502- filename='foo_0.5.11.tar.gz', filecontent='1')
503-
504- pub_2.sourcepackagerelease.addFile(shared_tarball_copy)
505- self.assertEquals(
506- 6, self.ppa.sources_size,
507- 'The sources_size should change after adding a duplicate file.')
508+ archive = self.factory.makeArchive()
509+ library_file = self.factory.makeLibraryFileAlias()
510+ self.publishSourceFile(archive, library_file)
511+ self.assertEquals(
512+ library_file.content.filesize, archive.sources_size)
513+
514+ self.publishSourceFile(archive, library_file)
515+ self.assertEquals(
516+ library_file.content.filesize, archive.sources_size)
517
518
519 class TestSeriesWithSources(TestCaseWithFactory):
520@@ -634,7 +615,6 @@
521 self.factory.makeComponent(),
522 PackagePublishingPocket.PROPOSED),
523 InvalidPocketForPPA)
524-
525 # XXX: JRV 20100511: IArchive.canUploadSuiteSourcePackage needs tests
526
527
528
529=== modified file 'lib/lp/testing/__init__.py'
530--- lib/lp/testing/__init__.py 2010-07-25 14:54:01 +0000
531+++ lib/lp/testing/__init__.py 2010-08-04 00:47:45 +0000
532@@ -79,7 +79,7 @@
533
534 from zope.component import adapter, getUtility
535 import zope.event
536-from zope.interface.verify import verifyClass, verifyObject
537+from zope.interface.verify import verifyClass
538 from zope.security.proxy import (
539 isinstance as zope_isinstance, removeSecurityProxy)
540 from zope.testing.testrunner.runner import TestResult as ZopeTestResult
541@@ -115,6 +115,7 @@
542 from lp.testing._tales import test_tales
543 from lp.testing._webservice import (
544 launchpadlib_credentials_for, launchpadlib_for, oauth_access_token_for)
545+from lp.testing.matchers import Provides
546 from lp.testing.fixture import ZopeEventHandlerFixture
547
548 # zope.exception demands more of frame objects than twisted.python.failure
549@@ -286,13 +287,7 @@
550
551 def assertProvides(self, obj, interface):
552 """Assert 'obj' correctly provides 'interface'."""
553- self.assertTrue(
554- interface.providedBy(obj),
555- "%r does not provide %r." % (obj, interface))
556- self.assertTrue(
557- verifyObject(interface, obj),
558- "%r claims to provide %r but does not do so correctly."
559- % (obj, interface))
560+ self.assertThat(obj, Provides(interface))
561
562 def assertClassImplements(self, cls, interface):
563 """Assert 'cls' may correctly implement 'interface'."""
564
565=== modified file 'lib/lp/testing/factory.py'
566--- lib/lp/testing/factory.py 2010-08-03 22:49:42 +0000
567+++ lib/lp/testing/factory.py 2010-08-04 00:47:45 +0000
568@@ -125,7 +125,7 @@
569 from lp.registry.interfaces.projectgroup import IProjectGroupSet
570 from lp.registry.interfaces.series import SeriesStatus
571 from lp.registry.interfaces.sourcepackage import (
572- ISourcePackage, SourcePackageUrgency)
573+ ISourcePackage, SourcePackageFileType, SourcePackageUrgency)
574 from lp.registry.interfaces.sourcepackagename import (
575 ISourcePackageNameSet)
576 from lp.registry.interfaces.ssh import ISSHKeySet
577@@ -143,18 +143,18 @@
578 from lp.soyuz.interfaces.archive import (
579 default_name_by_purpose, IArchiveSet, ArchivePurpose)
580 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
581-from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat
582+from lp.soyuz.interfaces.binarypackagerelease import (
583+ BinaryPackageFileType, BinaryPackageFormat)
584 from lp.soyuz.interfaces.component import IComponentSet
585 from lp.soyuz.interfaces.packageset import IPackagesetSet
586 from lp.soyuz.interfaces.processor import IProcessorFamilySet
587 from lp.soyuz.interfaces.publishing import (
588- PackagePublishingPriority, PackagePublishingStatus)
589+ IPublishingSet, PackagePublishingPriority, PackagePublishingStatus)
590 from lp.soyuz.interfaces.section import ISectionSet
591 from lp.soyuz.model.binarypackagename import BinaryPackageName
592 from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
593+from lp.soyuz.model.files import BinaryPackageFile, SourcePackageReleaseFile
594 from lp.soyuz.model.processor import ProcessorFamilySet
595-from lp.soyuz.model.publishing import (
596- BinaryPackagePublishingHistory, SourcePackagePublishingHistory)
597 from lp.testing import (
598 ANONYMOUS,
599 login,
600@@ -2349,6 +2349,19 @@
601 dateuploaded=date_uploaded,
602 source_package_recipe_build=source_package_recipe_build)
603
604+ def makeSourcePackageReleaseFile(self, sourcepackagerelease=None,
605+ library_file=None, filetype=None):
606+ if sourcepackagerelease is None:
607+ sourcepackagerelease = self.makeSourcePackageRelease()
608+ if library_file is None:
609+ library_file = self.makeLibraryFileAlias()
610+ if filetype is None:
611+ filetype = SourcePackageFileType.DSC
612+ return ProxyFactory(
613+ SourcePackageReleaseFile(
614+ sourcepackagerelease=sourcepackagerelease,
615+ libraryfile=library_file, filetype=filetype))
616+
617 def makeBinaryPackageBuild(self, source_package_release=None,
618 distroarchseries=None, archive=None, builder=None):
619 """Create a BinaryPackageBuild.
620@@ -2410,6 +2423,7 @@
621 dsc_standards_version='3.6.2',
622 dsc_format='1.0',
623 dsc_binaries='foo-bin',
624+ sourcepackagerelease=None,
625 ):
626 """Make a `SourcePackagePublishingHistory`."""
627 if distroseries is None:
628@@ -2430,36 +2444,37 @@
629 if status is None:
630 status = PackagePublishingStatus.PENDING
631
632- spr = self.makeSourcePackageRelease(
633- archive=archive,
634- sourcepackagename=sourcepackagename,
635- distroseries=distroseries,
636- maintainer=maintainer,
637- creator=creator, component=component,
638- section_name=section_name,
639- urgency=urgency,
640- version=version,
641- builddepends=builddepends,
642- builddependsindep=builddependsindep,
643- build_conflicts=build_conflicts,
644- build_conflicts_indep=build_conflicts_indep,
645- architecturehintlist=architecturehintlist,
646- dsc_standards_version=dsc_standards_version,
647- dsc_format=dsc_format,
648- dsc_binaries=dsc_binaries,
649- date_uploaded=date_uploaded)
650-
651- return ProxyFactory(SourcePackagePublishingHistory(
652- distroseries=distroseries,
653- sourcepackagerelease=spr,
654- component=spr.component,
655- section=spr.section,
656- status=status,
657- datecreated=date_uploaded,
658- dateremoved=dateremoved,
659- scheduleddeletiondate=scheduleddeletiondate,
660- pocket=pocket,
661- archive=archive))
662+ if sourcepackagerelease is None:
663+ sourcepackagerelease = self.makeSourcePackageRelease(
664+ archive=archive,
665+ sourcepackagename=sourcepackagename,
666+ distroseries=distroseries,
667+ maintainer=maintainer,
668+ creator=creator, component=component,
669+ section_name=section_name,
670+ urgency=urgency,
671+ version=version,
672+ builddepends=builddepends,
673+ builddependsindep=builddependsindep,
674+ build_conflicts=build_conflicts,
675+ build_conflicts_indep=build_conflicts_indep,
676+ architecturehintlist=architecturehintlist,
677+ dsc_standards_version=dsc_standards_version,
678+ dsc_format=dsc_format,
679+ dsc_binaries=dsc_binaries,
680+ date_uploaded=date_uploaded)
681+
682+ spph = getUtility(IPublishingSet).newSourcePublication(
683+ archive, sourcepackagerelease, distroseries,
684+ sourcepackagerelease.component, sourcepackagerelease.section,
685+ pocket)
686+
687+ naked_spph = removeSecurityProxy(spph)
688+ naked_spph.status = status
689+ naked_spph.datecreated = date_uploaded
690+ naked_spph.dateremoved = dateremoved
691+ naked_spph.scheduleddeletiondate = scheduleddeletiondate
692+ return spph
693
694 def makeBinaryPackagePublishingHistory(self, binarypackagerelease=None,
695 distroarchseries=None,
696@@ -2492,28 +2507,40 @@
697 if priority is None:
698 priority = PackagePublishingPriority.OPTIONAL
699
700- bpr = self.makeBinaryPackageRelease(
701- component=component,
702- section_name=section_name,
703- priority=priority)
704+ if binarypackagerelease is None:
705+ binarypackagerelease = self.makeBinaryPackageRelease(
706+ component=component,
707+ section_name=section_name,
708+ priority=priority)
709
710- return BinaryPackagePublishingHistory(
711- distroarchseries=distroarchseries,
712- binarypackagerelease=bpr,
713- component=bpr.component,
714- section=bpr.section,
715- status=status,
716- dateremoved=dateremoved,
717- scheduleddeletiondate=scheduleddeletiondate,
718- pocket=pocket,
719- priority=priority,
720- archive=archive)
721+ bpph = getUtility(IPublishingSet).newBinaryPublication(
722+ archive, binarypackagerelease, distroarchseries,
723+ binarypackagerelease.component, binarypackagerelease.section,
724+ priority, pocket)
725+ naked_bpph = removeSecurityProxy(bpph)
726+ naked_bpph.status = status
727+ naked_bpph.dateremoved = dateremoved
728+ naked_bpph.scheduleddeletiondate = scheduleddeletiondate
729+ naked_bpph.priority = priority
730+ return bpph
731
732 def makeBinaryPackageName(self, name=None):
733 if name is None:
734 name = self.getUniqueString("binarypackage")
735 return BinaryPackageName(name=name)
736
737+ def makeBinaryPackageFile(self, binarypackagerelease=None,
738+ library_file=None, filetype=None):
739+ if binarypackagerelease is None:
740+ binarypackagerelease = self.makeBinaryPackageRelease()
741+ if library_file is None:
742+ library_file = self.makeLibraryFileAlias()
743+ if filetype is None:
744+ filetype = BinaryPackageFileType.DEB
745+ return ProxyFactory(BinaryPackageFile(
746+ binarypackagerelease=binarypackagerelease,
747+ libraryfile=library_file, filetype=filetype))
748+
749 def makeBinaryPackageRelease(self, binarypackagename=None,
750 version=None, build=None,
751 binpackageformat=None, component=None,
752@@ -2538,13 +2565,13 @@
753 summary = self.getUniqueString("summary")
754 if description is None:
755 description = self.getUniqueString("description")
756- return BinaryPackageRelease(binarypackagename=binarypackagename,
757- version=version, build=build,
758- binpackageformat=binpackageformat,
759- component=component, section=section,
760- priority=priority, summary=summary,
761- description=description,
762- architecturespecific=architecturespecific)
763+ return ProxyFactory(
764+ BinaryPackageRelease(
765+ binarypackagename=binarypackagename, version=version,
766+ build=build, binpackageformat=binpackageformat,
767+ component=component, section=section, priority=priority,
768+ summary=summary, description=description,
769+ architecturespecific=architecturespecific))
770
771 def makeSection(self, name=None):
772 """Make a `Section`."""
773
774=== added file 'lib/lp/testing/matchers.py'
775--- lib/lp/testing/matchers.py 1970-01-01 00:00:00 +0000
776+++ lib/lp/testing/matchers.py 2010-08-04 00:47:45 +0000
777@@ -0,0 +1,135 @@
778+# Copyright 2010 Canonical Ltd. This software is licensed under the
779+# GNU Affero General Public License version 3 (see the file LICENSE).
780+
781+__metaclass__ = type
782+__all__ = [
783+ 'DoesNotProvide',
784+ 'DoesNotCorrectlyProvide',
785+ 'IsNotProxied',
786+ 'IsProxied',
787+ 'Provides',
788+ 'ProvidesAndIsProxied',
789+ ]
790+
791+from zope.interface.verify import verifyObject
792+from zope.interface.exceptions import (
793+ BrokenImplementation, BrokenMethodImplementation, DoesNotImplement)
794+from zope.security.proxy import builtin_isinstance, Proxy
795+
796+from testtools.matchers import Matcher, Mismatch
797+
798+
799+class DoesNotProvide(Mismatch):
800+ """An object does not provide an interface."""
801+
802+ def __init__(self, obj, interface):
803+ """Create a DoesNotProvide Mismatch.
804+
805+ :param obj: the object that does not match.
806+ :param interface: the Interface that the object was supposed to match.
807+ """
808+ self.obj = obj
809+ self.interface = interface
810+
811+ def describe(self):
812+ return "%r does not provide %r." % (self.obj, self.interface)
813+
814+
815+class DoesNotCorrectlyProvide(DoesNotProvide):
816+ """An object does not correctly provide an interface."""
817+
818+ def __init__(self, obj, interface, extra=None):
819+ """Create a DoesNotCorrectlyProvide Mismatch.
820+
821+ :param obj: the object that does not match.
822+ :param interface: the Interface that the object was supposed to match.
823+ :param extra: any extra information about the mismatch as a string,
824+ or None
825+ """
826+ super(DoesNotCorrectlyProvide, self).__init__(obj, interface)
827+ self.extra = extra
828+
829+ def describe(self):
830+ if self.extra is not None:
831+ extra = ": %s" % self.extra
832+ else:
833+ extra = "."
834+ return ("%r claims to provide %r, but does not do so correctly%s"
835+ % (self.obj, self.interface, extra))
836+
837+
838+class Provides(Matcher):
839+ """Test that an object provides a certain interface."""
840+
841+ def __init__(self, interface):
842+ """Create a Provides Matcher.
843+
844+ :param interface: the Interface that the object should provide.
845+ """
846+ self.interface = interface
847+
848+ def __str__(self):
849+ return "provides %r." % self.interface
850+
851+ def match(self, matchee):
852+ if not self.interface.providedBy(matchee):
853+ return DoesNotProvide(matchee, self.interface)
854+ passed = True
855+ extra = None
856+ try:
857+ if not verifyObject(self.interface, matchee):
858+ passed = False
859+ except (BrokenImplementation, BrokenMethodImplementation,
860+ DoesNotImplement), e:
861+ passed = False
862+ extra = str(e)
863+ if not passed:
864+ return DoesNotCorrectlyProvide(
865+ matchee, self.interface, extra=extra)
866+ return None
867+
868+
869+class IsNotProxied(Mismatch):
870+ """An object is not proxied."""
871+
872+ def __init__(self, obj):
873+ """Create an IsNotProxied Mismatch.
874+
875+ :param obj: the object that is not proxied.
876+ """
877+ self.obj = obj
878+
879+ def describe(self):
880+ return "%r is not proxied." % self.obj
881+
882+
883+class IsProxied(Matcher):
884+ """Check that an object is proxied."""
885+
886+ def __str__(self):
887+ return "Is proxied."
888+
889+ def match(self, matchee):
890+ if not builtin_isinstance(matchee, Proxy):
891+ return IsNotProxied(matchee)
892+ return None
893+
894+
895+class ProvidesAndIsProxied(Matcher):
896+ """Test that an object implements an interface, and is proxied."""
897+
898+ def __init__(self, interface):
899+ """Create a ProvidesAndIsProxied matcher.
900+
901+ :param interface: the Interface the object must provide.
902+ """
903+ self.interface = interface
904+
905+ def __str__(self):
906+ return "Provides %r and is proxied." % self.interface
907+
908+ def match(self, matchee):
909+ mismatch = Provides(self.interface).match(matchee)
910+ if mismatch is not None:
911+ return mismatch
912+ return IsProxied().match(matchee)
913
914=== modified file 'lib/lp/testing/sampledata.py'
915--- lib/lp/testing/sampledata.py 2010-07-17 15:52:19 +0000
916+++ lib/lp/testing/sampledata.py 2010-08-04 00:47:45 +0000
917@@ -9,8 +9,46 @@
918
919 __metaclass__ = type
920 __all__ = [
921+ 'BUILDD_ADMIN_USERNAME',
922+ 'CHROOT_LIBRARYFILEALIAS',
923+ 'HOARY_DISTROSERIES_NAME',
924+ 'I386_ARCHITECTURE_NAME',
925+ 'LAUNCHPAD_DBUSER_NAME',
926+ 'MAIN_COMPONENT_NAME',
927 'NO_PRIVILEGE_EMAIL',
928+ 'UBUNTU_DEVELOPER_ADMIN_NAME',
929+ 'UBUNTU_DISTRIBUTION_NAME',
930+ 'UBUNTU_UPLOAD_TEAM_NAME',
931+ 'UBUNTUTEST_DISTRIBUTION_NAME',
932+ 'WARTY_DISTROSERIES_NAME',
933+ 'WARTY_ONLY_SOURCEPACKAGENAME',
934+ 'WARTY_ONLY_SOURCEPACKAGEVERSION',
935+ 'WARTY_UPDATES_SUITE_NAME',
936 ]
937
938+# Please use names that reveal intent, rather than being purely
939+# descriptive, i.e. USER16_NAME isn't as good as
940+# UBUNTU_DEVELOPER_NAME. Where intent is tricky to convey in the
941+# name, please leave a comment as well.
942
943+# A user with buildd admin rights and upload rights to Ubuntu.
944+BUILDD_ADMIN_USERNAME = 'cprov'
945+# The LibraryFileAlias of a chroot for attaching to a DistroArchSeries
946+CHROOT_LIBRARYFILEALIAS = 1
947+HOARY_DISTROSERIES_NAME = 'hoary'
948+I386_ARCHITECTURE_NAME = 'i386'
949+LAUNCHPAD_DBUSER_NAME = 'launchpad'
950+MAIN_COMPONENT_NAME = 'main'
951 NO_PRIVILEGE_EMAIL = 'no-priv@canonical.com'
952+# A user that is an admin of ubuntu-team, which has upload rights
953+# to Ubuntu.
954+UBUNTU_DEVELOPER_ADMIN_NAME = 'name16'
955+UBUNTU_DISTRIBUTION_NAME = 'ubuntu'
956+# A team that has upload rights to Ubuntu
957+UBUNTU_UPLOAD_TEAM_NAME = 'ubuntu-team'
958+WARTY_DISTROSERIES_NAME = 'warty'
959+# A source package name and version for a package only published in
960+# warty
961+WARTY_ONLY_SOURCEPACKAGENAME = 'mozilla-firefox'
962+WARTY_ONLY_SOURCEPACKAGEVERSION = '0.9'
963+WARTY_UPDATES_SUITE_NAME = WARTY_DISTROSERIES_NAME + '-updates'
964
965=== modified file 'lib/lp/testing/tests/test_factory.py'
966--- lib/lp/testing/tests/test_factory.py 2010-07-26 12:58:13 +0000
967+++ lib/lp/testing/tests/test_factory.py 2010-08-04 00:47:45 +0000
968@@ -5,23 +5,88 @@
969
970 __metaclass__ = type
971
972+from datetime import datetime
973+import pytz
974 import unittest
975
976 from zope.component import getUtility
977 from zope.security.proxy import removeSecurityProxy
978
979 from canonical.launchpad.webapp.interfaces import ILaunchBag
980-from canonical.testing.layers import DatabaseFunctionalLayer
981+from canonical.testing.layers import (
982+ DatabaseFunctionalLayer, LaunchpadZopelessLayer)
983 from lp.code.enums import CodeImportReviewStatus
984+from lp.registry.interfaces.sourcepackage import SourcePackageFileType
985+from lp.services.worlddata.interfaces.language import ILanguage
986+from lp.soyuz.interfaces.binarypackagerelease import (
987+ BinaryPackageFileType, IBinaryPackageRelease)
988+from lp.soyuz.interfaces.files import (
989+ IBinaryPackageFile, ISourcePackageReleaseFile)
990+from lp.soyuz.interfaces.publishing import (
991+ IBinaryPackagePublishingHistory, ISourcePackagePublishingHistory,
992+ PackagePublishingPriority, PackagePublishingStatus)
993 from lp.testing import TestCaseWithFactory
994-from lp.services.worlddata.interfaces.language import ILanguage
995 from lp.testing.factory import is_security_proxied_or_harmless
996+from lp.testing.matchers import IsProxied, Provides, ProvidesAndIsProxied
997
998
999 class TestFactory(TestCaseWithFactory):
1000
1001 layer = DatabaseFunctionalLayer
1002
1003+ # loginAsAnyone
1004+ def test_loginAsAnyone(self):
1005+ # Login as anyone logs you in as any user.
1006+ person = self.factory.loginAsAnyone()
1007+ current_person = getUtility(ILaunchBag).user
1008+ self.assertIsNot(None, person)
1009+ self.assertEqual(person, current_person)
1010+
1011+ # makeBinaryPackagePublishingHistory
1012+ def test_makeBinaryPackagePublishingHistory_returns_IBPPH(self):
1013+ bpph = self.factory.makeBinaryPackagePublishingHistory()
1014+ self.assertThat(
1015+ removeSecurityProxy(bpph),
1016+ Provides(IBinaryPackagePublishingHistory))
1017+
1018+ def test_makeBinaryPackagePublishingHistory_returns_proxied(self):
1019+ bpph = self.factory.makeBinaryPackagePublishingHistory()
1020+ self.assertThat(bpph, IsProxied())
1021+
1022+ def test_makeBinaryPackagePublishingHistory_uses_status(self):
1023+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1024+ status=PackagePublishingStatus.PENDING)
1025+ self.assertEquals(PackagePublishingStatus.PENDING, bpph.status)
1026+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1027+ status=PackagePublishingStatus.PUBLISHED)
1028+ self.assertEquals(PackagePublishingStatus.PUBLISHED, bpph.status)
1029+
1030+ def test_makeBinaryPackagePublishingHistory_uses_dateremoved(self):
1031+ dateremoved = datetime.now(pytz.UTC)
1032+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1033+ dateremoved=dateremoved)
1034+ self.assertEquals(dateremoved, bpph.dateremoved)
1035+
1036+ def test_makeBinaryPackagePublishingHistory_scheduleddeletiondate(self):
1037+ scheduleddeletiondate = datetime.now(pytz.UTC)
1038+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1039+ scheduleddeletiondate=scheduleddeletiondate)
1040+ self.assertEquals(scheduleddeletiondate, bpph.scheduleddeletiondate)
1041+
1042+ def test_makeBinaryPackagePublishingHistory_uses_priority(self):
1043+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1044+ priority=PackagePublishingPriority.OPTIONAL)
1045+ self.assertEquals(PackagePublishingPriority.OPTIONAL, bpph.priority)
1046+ bpph = self.factory.makeBinaryPackagePublishingHistory(
1047+ priority=PackagePublishingPriority.EXTRA)
1048+ self.assertEquals(PackagePublishingPriority.EXTRA, bpph.priority)
1049+
1050+ # makeBinaryPackageRelease
1051+ def test_makeBinaryPackageRelease_returns_IBinaryPackageRelease(self):
1052+ bpr = self.factory.makeBinaryPackageRelease()
1053+ self.assertThat(bpr, ProvidesAndIsProxied(IBinaryPackageRelease))
1054+
1055+ # makeCodeImport
1056 def test_makeCodeImportNoStatus(self):
1057 # If makeCodeImport is not given a review status, it defaults to NEW.
1058 code_import = self.factory.makeCodeImport()
1059@@ -35,6 +100,7 @@
1060 code_import = self.factory.makeCodeImport(review_status=status)
1061 self.assertEqual(status, code_import.review_status)
1062
1063+ # makeLanguage
1064 def test_makeLanguage(self):
1065 # Without parameters, makeLanguage creates a language with code
1066 # starting with 'lang'.
1067@@ -61,12 +127,109 @@
1068 # And name is constructed from code as 'Language %(code)s'.
1069 self.assertEquals('Test language', language.englishname)
1070
1071- def test_loginAsAnyone(self):
1072- # Login as anyone logs you in as any user.
1073- person = self.factory.loginAsAnyone()
1074- current_person = getUtility(ILaunchBag).user
1075- self.assertIsNot(None, person)
1076- self.assertEqual(person, current_person)
1077+ # makeSourcePackagePublishingHistory
1078+ def test_makeSourcePackagePublishingHistory_returns_ISPPH(self):
1079+ spph = self.factory.makeSourcePackagePublishingHistory()
1080+ self.assertThat(
1081+ removeSecurityProxy(spph),
1082+ Provides(ISourcePackagePublishingHistory))
1083+
1084+ def test_makeSourcePackagePublishingHistory_returns_proxied(self):
1085+ spph = self.factory.makeSourcePackagePublishingHistory()
1086+ self.assertThat(spph, IsProxied())
1087+
1088+ def test_makeSourcePackagePublishingHistory_uses_spr(self):
1089+ spr = self.factory.makeSourcePackageRelease()
1090+ spph = self.factory.makeSourcePackagePublishingHistory(
1091+ sourcepackagerelease=spr)
1092+ self.assertEquals(spr, spph.sourcepackagerelease)
1093+
1094+ def test_makeSourcePackagePublishingHistory_uses_status(self):
1095+ spph = self.factory.makeSourcePackagePublishingHistory(
1096+ status=PackagePublishingStatus.PENDING)
1097+ self.assertEquals(PackagePublishingStatus.PENDING, spph.status)
1098+ spph = self.factory.makeSourcePackagePublishingHistory(
1099+ status=PackagePublishingStatus.PUBLISHED)
1100+ self.assertEquals(PackagePublishingStatus.PUBLISHED, spph.status)
1101+
1102+ def test_makeSourcePackagePublishingHistory_uses_date_uploaded(self):
1103+ date_uploaded = datetime.now(pytz.UTC)
1104+ spph = self.factory.makeSourcePackagePublishingHistory(
1105+ date_uploaded=date_uploaded)
1106+ self.assertEquals(date_uploaded, spph.datecreated)
1107+
1108+ def test_makeSourcePackagePublishingHistory_uses_dateremoved(self):
1109+ dateremoved = datetime.now(pytz.UTC)
1110+ spph = self.factory.makeSourcePackagePublishingHistory(
1111+ dateremoved=dateremoved)
1112+ self.assertEquals(dateremoved, spph.dateremoved)
1113+
1114+ def test_makeSourcePackagePublishingHistory_scheduleddeletiondate(self):
1115+ scheduleddeletiondate = datetime.now(pytz.UTC)
1116+ spph = self.factory.makeSourcePackagePublishingHistory(
1117+ scheduleddeletiondate=scheduleddeletiondate)
1118+ self.assertEquals(scheduleddeletiondate, spph.scheduleddeletiondate)
1119+
1120+
1121+class TestFactoryWithLibrarian(TestCaseWithFactory):
1122+
1123+ layer = LaunchpadZopelessLayer
1124+
1125+ # makeBinaryPackageFile
1126+ def test_makeBinaryPackageFile_returns_IBinaryPackageFile(self):
1127+ bpf = self.factory.makeBinaryPackageFile()
1128+ self.assertThat(bpf, ProvidesAndIsProxied(IBinaryPackageFile))
1129+
1130+ def test_makeBinaryPackageFile_uses_binarypackagerelease(self):
1131+ binarypackagerelease = self.factory.makeBinaryPackageRelease()
1132+ bpf = self.factory.makeBinaryPackageFile(
1133+ binarypackagerelease=binarypackagerelease)
1134+ self.assertEqual(binarypackagerelease, bpf.binarypackagerelease)
1135+
1136+ def test_makeBinaryPackageFile_uses_library_file(self):
1137+ library_file = self.factory.makeLibraryFileAlias()
1138+ bpf = self.factory.makeBinaryPackageFile(
1139+ library_file=library_file)
1140+ self.assertEqual(library_file, bpf.libraryfile)
1141+
1142+ def test_makeBinaryPackageFile_uses_filetype(self):
1143+ bpf = self.factory.makeBinaryPackageFile(
1144+ filetype=BinaryPackageFileType.DEB)
1145+ self.assertEqual(BinaryPackageFileType.DEB, bpf.filetype)
1146+ bpf = self.factory.makeBinaryPackageFile(
1147+ filetype=BinaryPackageFileType.DDEB)
1148+ self.assertEqual(BinaryPackageFileType.DDEB, bpf.filetype)
1149+
1150+ # makeSourcePackageReleaseFile
1151+ def test_makeSourcePackageReleaseFile_returns_ISPRF(self):
1152+ spr_file = self.factory.makeSourcePackageReleaseFile()
1153+ self.assertThat(
1154+ spr_file, ProvidesAndIsProxied(ISourcePackageReleaseFile))
1155+
1156+ def test_makeSourcePackageReleaseFile_uses_sourcepackagerelease(self):
1157+ spr = self.factory.makeSourcePackageRelease()
1158+ spr_file = self.factory.makeSourcePackageReleaseFile(
1159+ sourcepackagerelease=spr)
1160+ self.assertEqual(spr, spr_file.sourcepackagerelease)
1161+
1162+ def test_makeSourcePackageReleaseFile_uses_library_file(self):
1163+ library_file = self.factory.makeLibraryFileAlias()
1164+ spr_file = self.factory.makeSourcePackageReleaseFile(
1165+ library_file=library_file)
1166+ self.assertEqual(library_file, spr_file.libraryfile)
1167+
1168+ def test_makeSourcePackageReleaseFile_uses_filetype(self):
1169+ spr_file = self.factory.makeSourcePackageReleaseFile(
1170+ filetype=SourcePackageFileType.DIFF)
1171+ self.assertEqual(SourcePackageFileType.DIFF, spr_file.filetype)
1172+ spr_file = self.factory.makeSourcePackageReleaseFile(
1173+ filetype=SourcePackageFileType.DSC)
1174+ self.assertEqual(SourcePackageFileType.DSC, spr_file.filetype)
1175+
1176+
1177+class IsSecurityProxiedOrHarmlessTests(TestCaseWithFactory):
1178+
1179+ layer = DatabaseFunctionalLayer
1180
1181 def test_is_security_proxied_or_harmless__none(self):
1182 # is_security_proxied_or_harmless() considers the None object
1183
1184=== added file 'lib/lp/testing/tests/test_matchers.py'
1185--- lib/lp/testing/tests/test_matchers.py 1970-01-01 00:00:00 +0000
1186+++ lib/lp/testing/tests/test_matchers.py 2010-08-04 00:47:45 +0000
1187@@ -0,0 +1,171 @@
1188+# Copyright 2010 Canonical Ltd. This software is licensed under the
1189+# GNU Affero General Public License version 3 (see the file LICENSE).
1190+
1191+__metaclass__ = type
1192+
1193+from zope.interface import implements, Interface
1194+from zope.interface.verify import verifyObject
1195+from zope.interface.exceptions import BrokenImplementation
1196+from zope.security.checker import NamesChecker
1197+from zope.security.proxy import ProxyFactory
1198+
1199+from lp.testing import TestCase
1200+from lp.testing.matchers import (
1201+ DoesNotCorrectlyProvide, DoesNotProvide, IsNotProxied, IsProxied,
1202+ Provides, ProvidesAndIsProxied)
1203+
1204+
1205+class ITestInterface(Interface):
1206+ """A dummy interface for testing."""
1207+
1208+ def doFoo():
1209+ """Dummy method for interface compliance testing."""
1210+
1211+
1212+class Implementor:
1213+ """Dummy class that implements ITestInterface for testing."""
1214+
1215+ implements(ITestInterface)
1216+
1217+ def doFoo(self):
1218+ pass
1219+
1220+
1221+class DoesNotProvideTests(TestCase):
1222+
1223+ def test_describe(self):
1224+ obj = object()
1225+ mismatch = DoesNotProvide(obj, ITestInterface)
1226+ self.assertEqual(
1227+ "%r does not provide %r." % (obj, ITestInterface),
1228+ mismatch.describe())
1229+
1230+
1231+class DoesNotCorrectlyProvideMismatchTests(TestCase):
1232+
1233+ def test_describe(self):
1234+ obj = object()
1235+ mismatch = DoesNotCorrectlyProvide(obj, ITestInterface)
1236+ self.assertEqual(
1237+ "%r claims to provide %r, but does not do so correctly."
1238+ % (obj, ITestInterface),
1239+ mismatch.describe())
1240+
1241+ def test_describe_with_extra(self):
1242+ obj = object()
1243+ mismatch = DoesNotCorrectlyProvide(
1244+ obj, ITestInterface, extra="foo")
1245+ self.assertEqual(
1246+ "%r claims to provide %r, but does not do so correctly: foo"
1247+ % (obj, ITestInterface),
1248+ mismatch.describe())
1249+
1250+
1251+class ProvidesTests(TestCase):
1252+
1253+ def test_str(self):
1254+ matcher = Provides(ITestInterface)
1255+ self.assertEqual("provides %r." % ITestInterface, str(matcher))
1256+
1257+ def test_matches(self):
1258+ matcher = Provides(ITestInterface)
1259+ self.assertEqual(None, matcher.match(Implementor()))
1260+
1261+ def match_does_not_provide(self):
1262+ obj = object()
1263+ matcher = Provides(ITestInterface)
1264+ return obj, matcher.match(obj)
1265+
1266+ def test_mismatches_not_implements(self):
1267+ obj, mismatch = self.match_does_not_provide()
1268+ self.assertIsInstance(mismatch, DoesNotProvide)
1269+
1270+ def test_does_not_provide_sets_object(self):
1271+ obj, mismatch = self.match_does_not_provide()
1272+ self.assertEqual(obj, mismatch.obj)
1273+
1274+ def test_does_not_provide_sets_interface(self):
1275+ obj, mismatch = self.match_does_not_provide()
1276+ self.assertEqual(ITestInterface, mismatch.interface)
1277+
1278+ def match_does_not_verify(self):
1279+ class BadlyImplementedClass:
1280+ implements(ITestInterface)
1281+ obj = BadlyImplementedClass()
1282+ matcher = Provides(ITestInterface)
1283+ return obj, matcher.match(obj)
1284+
1285+ def test_mismatch_does_not_verify(self):
1286+ obj, mismatch = self.match_does_not_verify()
1287+ self.assertIsInstance(mismatch, DoesNotCorrectlyProvide)
1288+
1289+ def test_does_not_verify_sets_object(self):
1290+ obj, mismatch = self.match_does_not_verify()
1291+ self.assertEqual(obj, mismatch.obj)
1292+
1293+ def test_does_not_verify_sets_interface(self):
1294+ obj, mismatch = self.match_does_not_verify()
1295+ self.assertEqual(ITestInterface, mismatch.interface)
1296+
1297+ def test_does_not_verify_sets_extra(self):
1298+ obj, mismatch = self.match_does_not_verify()
1299+ try:
1300+ verifyObject(ITestInterface, obj)
1301+ self.assert_("verifyObject did not raise an exception.")
1302+ except BrokenImplementation, e:
1303+ extra = str(e)
1304+ self.assertEqual(extra, mismatch.extra)
1305+
1306+
1307+class IsNotProxiedTests(TestCase):
1308+
1309+ def test_describe(self):
1310+ obj = object()
1311+ mismatch = IsNotProxied(obj)
1312+ self.assertEqual("%r is not proxied." % obj, mismatch.describe())
1313+
1314+
1315+class IsProxiedTests(TestCase):
1316+
1317+ def test_str(self):
1318+ matcher = IsProxied()
1319+ self.assertEqual("Is proxied.", str(matcher))
1320+
1321+ def test_match(self):
1322+ obj = ProxyFactory(object(), checker=NamesChecker())
1323+ self.assertEqual(None, IsProxied().match(obj))
1324+
1325+ def test_mismatch(self):
1326+ obj = object()
1327+ self.assertIsInstance(IsProxied().match(obj), IsNotProxied)
1328+
1329+ def test_mismatch_sets_object(self):
1330+ obj = object()
1331+ mismatch = IsProxied().match(obj)
1332+ self.assertEqual(obj, mismatch.obj)
1333+
1334+
1335+class ProvidesAndIsProxiedTests(TestCase):
1336+
1337+ def test_str(self):
1338+ matcher = ProvidesAndIsProxied(ITestInterface)
1339+ self.assertEqual(
1340+ "Provides %r and is proxied." % ITestInterface,
1341+ str(matcher))
1342+
1343+ def test_match(self):
1344+ obj = ProxyFactory(
1345+ Implementor(), checker=NamesChecker(names=("doFoo",)))
1346+ matcher = ProvidesAndIsProxied(ITestInterface)
1347+ self.assertThat(obj, matcher)
1348+ self.assertEqual(None, matcher.match(obj))
1349+
1350+ def test_mismatch_unproxied(self):
1351+ obj = Implementor()
1352+ matcher = ProvidesAndIsProxied(ITestInterface)
1353+ self.assertIsInstance(matcher.match(obj), IsNotProxied)
1354+
1355+ def test_mismatch_does_not_implement(self):
1356+ obj = ProxyFactory(object(), checker=NamesChecker())
1357+ matcher = ProvidesAndIsProxied(ITestInterface)
1358+ self.assertIsInstance(matcher.match(obj), DoesNotProvide)