← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/replace-archiveuploader-doctests-0 into lp:launchpad/devel

 

William Grant has proposed merging lp:~wgrant/launchpad/replace-archiveuploader-doctests-0 into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)


Three things:

 - Replaces some archiveuploader doctest sections with unit tests.
 - Removes a couple of attributes from NascentUpload that were used by only one test -- that test now calculates them itself.
 - Moves some missed archiveuploader doctests from lp.soyuz to lp.archiveuploader.
-- 
https://code.launchpad.net/~wgrant/launchpad/replace-archiveuploader-doctests-0/+merge/30850
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/replace-archiveuploader-doctests-0 into lp:launchpad/devel.
=== modified file 'lib/lp/archiveuploader/nascentupload.py'
--- lib/lp/archiveuploader/nascentupload.py	2010-07-15 09:42:28 +0000
+++ lib/lp/archiveuploader/nascentupload.py	2010-07-24 09:41:13 +0000
@@ -82,10 +82,6 @@
     archindep = False
     archdep = False
 
-    # Defined in check_sourceful_consistency()
-    native = False
-    hasorig = False
-
     # Defined if we successfully do_accept() and storeObjectsInDatabase()
     queue_root = None
 
@@ -308,31 +304,17 @@
         assert self.sourceful, (
             "Source consistency check called for a non-source upload")
 
-        dsc = 0
-        native_tarball = 0
-        orig_tarball = 0
-
-        for uploaded_file in self.changes.files:
-            filetype = determine_source_file_type(uploaded_file.filename)
-            if filetype == SourcePackageFileType.DSC:
-                dsc += 1
-            elif (filetype == SourcePackageFileType.NATIVE_TARBALL
-                  and not isinstance(uploaded_file, CustomUploadFile)):
-                native_tarball += 1
-            elif filetype == SourcePackageFileType.ORIG_TARBALL:
-                orig_tarball += 1
-
+        dsc = len([
+            file for file in self.changes.files
+            if determine_source_file_type(file.filename) ==
+                SourcePackageFileType.DSC])
 
         # It is never sane to upload more than one source at a time.
         if dsc > 1:
             self.reject("Changes file lists more than one .dsc")
-
         if dsc == 0:
             self.reject("Sourceful upload without a .dsc")
 
-        self.native = bool(native_tarball)
-        self.hasorig = bool(orig_tarball)
-
     def _check_binaryful_consistency(self):
         """Heuristic checks on a binaryful upload.
 

=== renamed file 'lib/lp/soyuz/doc/nascentupload-announcements.txt' => 'lib/lp/archiveuploader/tests/nascentupload-announcements.txt'
--- lib/lp/soyuz/doc/nascentupload-announcements.txt	2010-05-27 09:08:10 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-announcements.txt	2010-07-24 09:41:13 +0000
@@ -39,6 +39,8 @@
 
 We need to be logged into the security model in order to get any further
 
+  >>> from canonical.testing.layers import LaunchpadZopelessLayer
+  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
   >>> login('foo.bar@xxxxxxxxxxxxx')
 
 Helper functions to examine emails that were sent:
@@ -58,17 +60,12 @@
 address and allow uploads to universe:
 
   >>> from canonical.launchpad.interfaces import (
-  ...     SeriesStatus, IComponentSet, IDistributionSet,
-  ...     ILibraryFileAliasSet)
+  ...     SeriesStatus, IDistributionSet, ILibraryFileAliasSet)
   >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
   >>> hoary = ubuntu['hoary']
   >>> hoary.status = SeriesStatus.DEVELOPMENT
   >>> hoary.changeslist = "hoary-announce@xxxxxxxxxxxxxxxx"
-  >>> from canonical.launchpad.database import ComponentSelection
-  >>> universe = getUtility(IComponentSet)['universe']
-  >>> trash = ComponentSelection(distroseries=hoary, component=universe)
   >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1]
-  >>> trash = hoary['i386'].addOrUpdateChroot(fake_chroot)
   >>> trash = hoary['hppa'].addOrUpdateChroot(fake_chroot)
 
 NEW source upload to RELEASE pocket via 'sync' policy (it presents

=== renamed file 'lib/lp/soyuz/doc/nascentupload-security-uploads.txt' => 'lib/lp/archiveuploader/tests/nascentupload-security-uploads.txt'
--- lib/lp/soyuz/doc/nascentupload-security-uploads.txt	2009-05-13 14:05:27 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-security-uploads.txt	2010-07-24 09:41:13 +0000
@@ -31,6 +31,8 @@
 respective processorfamily and processor. Let's create them
 on-the-fly:
 
+  >>> from canonical.testing.layers import LaunchpadZopelessLayer
+  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
   >>> from canonical.launchpad.interfaces import IDistributionSet
   >>> from canonical.launchpad.database import (
   ...    Processor, ProcessorFamily)
@@ -45,6 +47,7 @@
 
   >>> import transaction
   >>> transaction.commit()
+  >>> LaunchpadZopelessLayer.switchDbUser('uploader')
 
 
 == Mixed Security Upload ==

=== renamed file 'lib/lp/soyuz/doc/nascentupload.txt' => 'lib/lp/archiveuploader/tests/nascentupload.txt'
--- lib/lp/soyuz/doc/nascentupload.txt	2010-05-21 12:12:58 +0000
+++ lib/lp/archiveuploader/tests/nascentupload.txt	2010-07-24 09:41:13 +0000
@@ -10,27 +10,13 @@
   >>> login('foo.bar@xxxxxxxxxxxxx')
 
 For the purpose of this test, hoary needs to be an open (development)
-distroseries so that we can upload to it.  It also needs to allow uploads
-to the universe component.
-
-This test normally runs as the "uploader" db user but it does not have
-permission to add a new ComponentSelection, so we temporarily switch to
-"launchpad" to handle this.
+distroseries so that we can upload to it.
 
   >>> from canonical.launchpad.interfaces import (
-  ...     SeriesStatus, IComponentSet, IDistributionSet)
-  >>> from canonical.launchpad.database import ComponentSelection
+  ...     SeriesStatus, IDistributionSet)
   >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
   >>> hoary = ubuntu['hoary']
   >>> hoary.status = SeriesStatus.DEVELOPMENT
-  >>> universe = getUtility(IComponentSet)['universe']
-  >>> from canonical.testing import LaunchpadZopelessLayer
-  >>> from canonical.database.sqlbase import commit
-  >>> commit()
-  >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
-  >>> trash = ComponentSelection(distroseries=hoary, component=universe)
-  >>> commit()
-  >>> LaunchpadZopelessLayer.switchDbUser('uploader')
 
 A NascentUpload is a collection of files in a directory. They
 represent what may turn out to be an acceptable upload to a launchpad
@@ -152,9 +138,21 @@
 
 ed_source is uses ORIG + DIFF form:
 
-  >>> ed_source_upload.native
+  >>> from lp.archiveuploader.utils import determine_source_file_type
+  >>> from lp.registry.interfaces.sourcepackage import SourcePackageFileType
+  >>> def determine_file_types(upload):
+  ...     return [determine_source_file_type(uf.filename)
+  ...             for uf in upload.changes.files]
+  >>> def has_orig(upload):
+  ...     return (SourcePackageFileType.ORIG_TARBALL
+  ...             in determine_file_types(upload))
+  >>> def has_native(upload):
+  ...     return (SourcePackageFileType.NATIVE_TARBALL
+  ...             in determine_file_types(upload))
+
+  >>> has_native(ed_source_upload)
   False
-  >>> ed_source_upload.hasorig
+  >>> has_orig(ed_source_upload)
   True
 
 For *sourceful* uploads 'archdep' and 'archindep' are always False:
@@ -197,9 +195,9 @@
 As expected 'native' and 'hasorig' doesn't make any sense for binary
 uploads, so they are alway False:
 
-  >>> ed_binary_upload.native
+  >>> has_native(ed_binary_upload)
   False
-  >>> ed_binary_upload.hasorig
+  >>> has_orig(ed_binary_upload)
   False
 
 Since the binary policy lets things through unsigned, we don't try and
@@ -287,9 +285,9 @@
 ancestries (it saves a lot of bandwidth). So, the upload is not
 'native', neither 'hasorig':
 
-  >>> ed_mixed_upload.native
+  >>> has_native(ed_mixed_upload)
   False
-  >>> ed_mixed_upload.hasorig
+  >>> has_orig(ed_mixed_upload)
   False
 
 But if we check the DSC we will find the reference to the already
@@ -716,7 +714,9 @@
 to set hoary to CURRENT in order to do this because we're not allowed
 to upload to -UPDATES in a DEVELOPMENT series.
 
+  >>> from canonical.testing import LaunchpadZopelessLayer
   >>> LaunchpadZopelessLayer.switchDbUser('launchpad')
+  >>> from canonical.database.sqlbase import commit
   >>> hoary.status = SeriesStatus.CURRENT
   >>> commit()
   >>> LaunchpadZopelessLayer.switchDbUser('uploader')

=== modified file 'lib/lp/archiveuploader/tests/nascentuploadfile.txt'
--- lib/lp/archiveuploader/tests/nascentuploadfile.txt	2010-06-16 09:08:16 +0000
+++ lib/lp/archiveuploader/tests/nascentuploadfile.txt	2010-07-24 09:41:13 +0000
@@ -155,161 +155,10 @@
 
 === CustomUploadFile identification ===
 
-Source and Binary files are easily recognized by a regexp on the
-filenames:
-
-    >>> from lp.archiveuploader.utils import (
-    ...     re_isadeb, re_issource)
-
-The binary regexp matches 'deb', 'ddeb' and 'udeb' filenames.
-
-    >>> deb_match = re_isadeb.match('foo-bar_1.0_i386.deb')
-    >>> deb_match.group(0)
-    'foo-bar_1.0_i386.deb'
-    >>> deb_match.group(1)
-    'foo-bar'
-    >>> deb_match.group(2)
-    '1.0'
-    >>> deb_match.group(3)
-    'i386'
-
-    >>> ddeb_match = re_isadeb.match('foo-bar_1.0_i386.ddeb')
-    >>> ddeb_match.group(0)
-    'foo-bar_1.0_i386.ddeb'
-    >>> ddeb_match.group(1)
-    'foo-bar'
-    >>> ddeb_match.group(2)
-    '1.0'
-    >>> ddeb_match.group(3)
-    'i386'
-
-    >>> udeb_match = re_isadeb.match('foo-bar_1.0_i386.udeb')
-    >>> udeb_match.group(0)
-    'foo-bar_1.0_i386.udeb'
-    >>> udeb_match.group(1)
-    'foo-bar'
-    >>> udeb_match.group(2)
-    '1.0'
-    >>> udeb_match.group(3)
-    'i386'
-
-The source regexp matches 'orig.tar.gz', 'tar.gz', 'diff.gz' and 'dsc'
-filenames.
-
-    >>> src_match = re_issource.match('foo_1.0.orig.tar.gz')
-    >>> src_match.group(0)
-    'foo_1.0.orig.tar.gz'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'orig.tar.gz'
-
-    >>> src_match = re_issource.match('foo_1.0.tar.gz')
-    >>> src_match.group(0)
-    'foo_1.0.tar.gz'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'tar.gz'
-
-    >>> src_match = re_issource.match('foo_1.0.tar.bz2')
-    >>> src_match.group(0)
-    'foo_1.0.tar.bz2'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'tar.bz2'
-
-    >>> src_match = re_issource.match('foo_1.0.diff.gz')
-    >>> src_match.group(0)
-    'foo_1.0.diff.gz'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'diff.gz'
-
-    >>> src_match = re_issource.match('foo_1.0.dsc')
-    >>> src_match.group(0)
-    'foo_1.0.dsc'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'dsc'
-
-    >>> src_match = re_issource.match('foo_1.0.debian.tar.gz')
-    >>> src_match.group(0)
-    'foo_1.0.debian.tar.gz'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'debian.tar.gz'
-
-    >>> src_match = re_issource.match('foo_1.0.debian.tar.bz2')
-    >>> src_match.group(0)
-    'foo_1.0.debian.tar.bz2'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'debian.tar.bz2'
-
-    >>> src_match = re_issource.match('foo_1.0.orig-foo.tar.gz')
-    >>> src_match.group(0)
-    'foo_1.0.orig-foo.tar.gz'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'orig-foo.tar.gz'
-
-    >>> src_match = re_issource.match('foo_1.0.orig-bar.tar.bz2')
-    >>> src_match.group(0)
-    'foo_1.0.orig-bar.tar.bz2'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0'
-    >>> src_match.group(3)
-    'orig-bar.tar.bz2'
-
-    >>> src_match = re_issource.match('foo_1.0.porig-bar.tar.bz2')
-    >>> src_match.group(0)
-    'foo_1.0.porig-bar.tar.bz2'
-    >>> src_match.group(1)
-    'foo'
-    >>> src_match.group(2)
-    '1.0.porig-bar'
-    >>> src_match.group(3)
-    'tar.bz2'
-
-And finally some failures:
-
-    >>> re_isadeb.match('foo-bar_1.0_i386.bed') is None
-    True
-
-    >>> re_issource.match('foo_1.0.c') is None
-    True
-
-    >>> re_issource.match('foo_1.0.diff.bz2') is None
-    True
-
-However a custom upload is essencially a tarball, so it also matches
-the is_source regexp:
-
+A custom upload is essentially a tarball, so it matches the is_source
+regexp, even though it isn't actually a source file:
+
+    >>> from lp.archiveuploader.utils import re_issource
     >>> src_match = re_issource.match('dist-upgrader_1.0.tar.gz')
     >>> src_match.group(0)
     'dist-upgrader_1.0.tar.gz'
@@ -600,115 +449,6 @@
     ['File ed_0.2-20.dsc mentioned in the changes has a size mismatch. 578 != 500']
 
 
-=== Format file type verification ===
-
-DSCFile performs additional verification on the types of the referenced
-files, confirming that they are suitable for the source package's
-format. There is an error generator to verify each format.
-
-   >>> from lp.archiveuploader.dscfile import (check_format_1_0_files,
-   ...     check_format_3_0_native_files, check_format_3_0_quilt_files)
-   >>> from lp.registry.interfaces.sourcepackage import SourcePackageFileType
-
-==== 1.0 ==== 
-
-A 1.0 source can contain either a tar.gz or an orig.tar.gz and diff.gz.
-
-   >>> list(check_format_1_0_files('foo_1.dsc', {
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DIFF: 1,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     SourcePackageFileType.NATIVE_TARBALL: 0,
-   ...     }, {}, 0))
-   []
-
-   >>> list(check_format_1_0_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 0,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     }, {}, 0))
-   []
-
-But if we have some other combination, or bzip2 compression, errors
-will be generated.
-
-   >>> list(check_format_1_0_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DIFF: 1,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     }, {}, 1))
-   [UploadError('foo_1.dsc: is format 1.0 but uses bzip2 compression.',), UploadError('foo_1.dsc: must have exactly one tar.gz, or an orig.tar.gz and diff.gz',)]
-
-The files are also bad if there are any components:
-
-   >>> list(check_format_1_0_files('foo_1.dsc', {
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DIFF: 1,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     SourcePackageFileType.NATIVE_TARBALL: 0,
-   ...     }, {'foo': 1}, 0))
-   [UploadError('foo_1.dsc: must have exactly one tar.gz, or an orig.tar.gz and diff.gz',)]
-
-==== 3.0 (native) ==== 
-
-A 3.0 (native) source must contain just a tar.(gz|bz2).
-
-   >>> list(check_format_3_0_native_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 0,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     }, {}, 1))
-   []
-
-   >>> list(check_format_3_0_native_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     }, {}, 1))
-   [UploadError('foo_1.dsc: must have only a tar.*.',)]
-
-   >>> list(check_format_3_0_native_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 0,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 0,
-   ...     }, {'foo': 1}, 0))
-   [UploadError('foo_1.dsc: must have only a tar.*.',)]
-
-==== 3.0 (quilt) ==== 
-
-A 3.0 (quilt) source must have an orig.tar.*, a debian.tar.*, and at
-most one orig-COMPONENT.tar.* for each COMPONENT.
-
-   >>> list(check_format_3_0_quilt_files('foo_1.dsc', {
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 1,
-   ...     SourcePackageFileType.NATIVE_TARBALL: 0,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     }, {'foo': 1}, 1))
-   []
-
-   >>> list(check_format_3_0_quilt_files('foo_1.dsc', {
-   ...     SourcePackageFileType.NATIVE_TARBALL: 1,
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 1,
-   ...     }, {}, 1))
-   [UploadError('foo_1.dsc: must have only an orig.tar.*, a debian.tar.*, and optionally orig-*.tar.*',)]
-
-   >>> list(check_format_3_0_quilt_files('foo_1.dsc', {
-   ...     SourcePackageFileType.ORIG_TARBALL: 1,
-   ...     SourcePackageFileType.DEBIAN_TARBALL: 1,
-   ...     SourcePackageFileType.NATIVE_TARBALL: 0,
-   ...     SourcePackageFileType.DIFF: 0,
-   ...     }, {'foo': 2}, 0))
-   [UploadError('foo_1.dsc: has more than one orig-foo.tar.*.',)]
-
-
 === Sub-DSC files or DSCUploadedFiles ===
 
 Sub-DSCFiles are DSCUploadedFile objects.

=== renamed file 'lib/lp/soyuz/doc/safe_fix_maintainer.txt' => 'lib/lp/archiveuploader/tests/safe_fix_maintainer.txt'
=== modified file 'lib/lp/archiveuploader/tests/test_dscfile.py'
--- lib/lp/archiveuploader/tests/test_dscfile.py	2010-07-20 15:25:30 +0000
+++ lib/lp/archiveuploader/tests/test_dscfile.py	2010-07-24 09:41:13 +0000
@@ -7,16 +7,22 @@
 
 import os
 
-from canonical.config import config
 from canonical.launchpad.scripts.logger import QuietFakeLogger
 from canonical.testing.layers import LaunchpadZopelessLayer
 from lp.archiveuploader.dscfile import (
-    DSCFile, findChangelog, findCopyright)
+    DSCFile, findChangelog, findCopyright, format_to_file_checker_map)
 from lp.archiveuploader.nascentuploadfile import UploadError
 from lp.archiveuploader.tests import datadir, mock_logger_quiet
 from lp.archiveuploader.uploadpolicy import BuildDaemonUploadPolicy
+from lp.registry.interfaces.sourcepackage import SourcePackageFileType
+from lp.soyuz.interfaces.sourcepackageformat import SourcePackageFormat
 from lp.testing import TestCase, TestCaseWithFactory
 
+ORIG_TARBALL = SourcePackageFileType.ORIG_TARBALL
+DEBIAN_TARBALL = SourcePackageFileType.DEBIAN_TARBALL
+NATIVE_TARBALL = SourcePackageFileType.NATIVE_TARBALL
+DIFF = SourcePackageFileType.DIFF
+
 
 class TestDscFile(TestCase):
 
@@ -146,3 +152,132 @@
                 dsc_file.cleanUp()
         finally:
             os.chmod(tempdir, 0755)
+
+
+class BaseTestSourceFileVerification(TestCase):
+
+    def assertErrorsForFiles(self, expected, files, components={},
+                             bzip2_count=0):
+        """Check problems with the given set of files for the given format.
+
+        :param expected: a list of expected errors, as strings.
+        :param format: the `SourcePackageFormat` to check against.
+        :param files: a dict mapping `SourcePackageFileType`s to counts.
+        :param components: a dict mapping orig component tarball components
+            to counts.
+        :param bzip2_count: number of files using bzip2 compression.
+        """
+        full_files = {
+            NATIVE_TARBALL: 0,
+            ORIG_TARBALL: 0,
+            DIFF: 0,
+            DEBIAN_TARBALL: 0,
+            }
+        full_files.update(files)
+        self.assertEquals(
+            expected,
+            [str(e) for e in format_to_file_checker_map[self.format](
+                'foo_1.dsc', full_files, components, bzip2_count)])
+
+    def assertFilesOK(self, files, components={}, bzip2_count=0):
+        """Check that the given set of files is OK for the given format.
+
+        :param format: the `SourcePackageFormat` to check against.
+        :param files: a dict mapping `SourcePackageFileType`s to counts.
+        :param components: a dict mapping orig component tarball components
+            to counts.
+        :param bzip2_count: number of files using bzip2 compression.
+        """
+        self.assertErrorsForFiles([], files, components, bzip2_count)
+
+
+class Test10SourceFormatVerification(BaseTestSourceFileVerification):
+
+    format = SourcePackageFormat.FORMAT_1_0
+
+    wrong_files_error = ('foo_1.dsc: must have exactly one tar.gz, or an '
+                         'orig.tar.gz and diff.gz')
+    bzip2_error = 'foo_1.dsc: is format 1.0 but uses bzip2 compression.'
+
+    def testFormat10Debian(self):
+        # A 1.0 source can contain an original tarball and a Debian diff
+        self.assertFilesOK({ORIG_TARBALL: 1, DIFF: 1})
+
+    def testFormat10Native(self):
+        # A 1.0 source can contain a native tarball.
+        self.assertFilesOK({NATIVE_TARBALL: 1})
+
+    def testFormat10CannotHaveWrongFiles(self):
+        # A 1.0 source cannot have a combination of native and
+        # non-native files, and cannot have just one of the non-native
+        # files.
+        for combination in (
+            {DIFF: 1}, {ORIG_TARBALL: 1}, {ORIG_TARBALL: 1, DIFF: 1,
+            NATIVE_TARBALL: 1}):
+            self.assertErrorsForFiles([self.wrong_files_error], combination)
+
+        # A 1.0 source with component tarballs is invalid.
+        self.assertErrorsForFiles(
+            [self.wrong_files_error], {ORIG_TARBALL: 1, DIFF: 1}, {'foo': 1})
+
+    def testFormat10CannotUseBzip2(self):
+        # 1.0 sources cannot use bzip2 compression.
+        self.assertErrorsForFiles(
+            [self.bzip2_error], {NATIVE_TARBALL: 1}, {}, 1)
+
+
+class Test30QuiltSourceFormatVerification(BaseTestSourceFileVerification):
+
+    format = SourcePackageFormat.FORMAT_3_0_QUILT
+
+    wrong_files_error = ('foo_1.dsc: must have only an orig.tar.*, a '
+                         'debian.tar.* and optionally orig-*.tar.*')
+    comp_conflict_error = 'foo_1.dsc: has more than one orig-bar.tar.*.'
+
+    def testFormat30Quilt(self):
+        # A 3.0 (quilt) source must contain an orig tarball and a debian
+        # tarball. It may also contain at most one component tarball for
+        # each component, and can use gzip or bzip2 compression.
+        for components in ({}, {'foo': 1}, {'foo': 1, 'bar': 1}):
+            for bzip2_count in (0, 1):
+                self.assertFilesOK(
+                    {ORIG_TARBALL: 1, DEBIAN_TARBALL: 1}, components,
+                    bzip2_count)
+
+    def testFormat30QuiltCannotHaveConflictingComponentTarballs(self):
+        # Multiple conflicting tarballs for a single component are
+        # invalid.
+        self.assertErrorsForFiles(
+            [self.comp_conflict_error],
+            {ORIG_TARBALL: 1, DEBIAN_TARBALL: 1}, {'foo': 1, 'bar': 2})
+
+    def testFormat30QuiltCannotHaveWrongFiles(self):
+        # 3.0 (quilt) sources may not have a diff or native tarball.
+        for filetype in (DIFF, NATIVE_TARBALL):
+            self.assertErrorsForFiles(
+                [self.wrong_files_error],
+                {ORIG_TARBALL: 1, DEBIAN_TARBALL: 1, filetype: 1})
+
+
+class Test30QuiltSourceFormatVerification(BaseTestSourceFileVerification):
+
+    format = SourcePackageFormat.FORMAT_3_0_NATIVE
+
+    wrong_files_error = 'foo_1.dsc: must have only a tar.*.'
+
+    def testFormat30Native(self):
+        # 3.0 (native) sources must contain just a native tarball. They
+        # may use gzip or bzip2 compression.
+        for bzip2_count in (0, 1):
+            self.assertFilesOK({NATIVE_TARBALL: 1}, {},
+            bzip2_count)
+
+    def testFormat30NativeCannotHaveWrongFiles(self):
+        # 3.0 (quilt) sources may not have a diff, Debian tarball, orig
+        # tarball, or any component tarballs.
+        for filetype in (DIFF, DEBIAN_TARBALL, ORIG_TARBALL):
+            self.assertErrorsForFiles(
+                [self.wrong_files_error], {NATIVE_TARBALL: 1, filetype: 1})
+        # A 3.0 (native) source with component tarballs is invalid.
+        self.assertErrorsForFiles(
+            [self.wrong_files_error], {NATIVE_TARBALL: 1}, {'foo': 1})

=== modified file 'lib/lp/archiveuploader/tests/test_utils.py'
--- lib/lp/archiveuploader/tests/test_utils.py	2010-07-18 00:26:33 +0000
+++ lib/lp/archiveuploader/tests/test_utils.py	2010-07-24 09:41:13 +0000
@@ -5,23 +5,19 @@
 
 # arch-tag: 90e6eb79-83a2-47e8-9f8b-3c687079c923
 
-import unittest
-import sys
+from testtools import TestCase
 
 from lp.registry.interfaces.sourcepackage import SourcePackageFileType
 from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType
 from lp.archiveuploader.tests import datadir
-
-
-class TestUtilities(unittest.TestCase):
-
-    def testImport(self):
-        """lp.archiveuploader.utils should be importable"""
-        import lp.archiveuploader.utils
+from lp.archiveuploader.utils import (determine_binary_file_type,
+    determine_source_file_type, re_isadeb, re_issource)
+
+
+class TestUtilities(TestCase):
 
     def test_determine_source_file_type(self):
         """lp.archiveuploader.utils.determine_source_file_type should work."""
-        from lp.archiveuploader.utils import determine_source_file_type
 
         # .dsc -> DSC
         self.assertEquals(
@@ -74,8 +70,6 @@
 
     def test_determine_binary_file_type(self):
         """lp.archiveuploader.utils.determine_binary_file_type should work."""
-        from lp.archiveuploader.utils import determine_binary_file_type
-
         # .deb -> DEB
         self.assertEquals(
             determine_binary_file_type('foo_1.0-1_all.deb'),
@@ -222,20 +216,43 @@
                 pass
 
 
-def test_suite():
-    suite = unittest.TestSuite()
-    loader = unittest.TestLoader()
-    suite.addTest(loader.loadTestsFromTestCase(TestUtilities))
-    return suite
-
-
-def main(argv):
-    suite = test_suite()
-    runner = unittest.TextTestRunner(verbosity = 2)
-    if not runner.run(suite).wasSuccessful():
-        return 1
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
+class TestFilenameRegularExpressions(TestCase):
+
+    def test_re_isadeb(self):
+        # Verify that the three binary extensions match the regexp.
+        for extension in ('deb', 'ddeb', 'udeb'):
+            self.assertEquals(
+                ('foo-bar', '1.0', 'i386', extension),
+                re_isadeb.match('foo-bar_1.0_i386.%s' % extension).groups())
+
+        # Some other extension doesn't match.
+        self.assertIs(None, re_isadeb.match('foo-bar_1.0_i386.notdeb'))
+
+        # A missing architecture also doesn't match.
+        self.assertIs(None, re_isadeb.match('foo-bar_1.0.deb'))
+
+    def test_re_issource(self):
+        # Verify that various source extensions match the regexp.
+        extensions = (
+            'dsc', 'tar.gz', 'tar.bz2', 'diff.gz', 'orig.tar.gz',
+            'orig.tar.bz2', 'orig-bar.tar.gz', 'orig-bar.tar.bz2',
+            'debian.tar.gz', 'debian.tar.bz2')
+        for extension in extensions:
+            self.assertEquals(
+                ('foo-bar', '1.0', extension),
+                re_issource.match('foo-bar_1.0.%s' % extension).groups())
+
+        # While orig-*.tar.gz is all interpreted as extension, *orig-*.tar.gz
+        # is taken to have an extension of just 'tar.gz'.
+        self.assertEquals(
+            ('foo-bar', '1.0.porig-bar', 'tar.gz'),
+            re_issource.match('foo-bar_1.0.porig-bar.tar.gz').groups())
+
+        # Some other extension doesn't match.
+        self.assertIs(None, re_issource.match('foo-bar_1.0.notdsc'))
+
+        # A badly formatted name also doesn't match.
+        self.assertIs(None, re_issource.match('foo-bar.dsc'))
+
+        # bzip2 compression for files which must be gzipped is invalid.
+        self.assertIs(None, re_issource.match('foo-bar_1.0.diff.bz2'))

=== renamed file 'lib/lp/soyuz/doc/uploadpolicy.txt' => 'lib/lp/archiveuploader/tests/uploadpolicy.txt'
=== modified file 'lib/lp/soyuz/tests/test_doc.py'
--- lib/lp/soyuz/tests/test_doc.py	2010-04-30 09:49:59 +0000
+++ lib/lp/soyuz/tests/test_doc.py	2010-07-24 09:41:13 +0000
@@ -123,11 +123,6 @@
 
 
 special = {
-    'nascentupload.txt': LayeredDocFileSuite(
-        '../doc/nascentupload.txt',
-        setUp=uploaderSetUp, tearDown=uploaderTearDown,
-        layer=LaunchpadZopelessLayer,
-        ),
     'build-notification.txt': LayeredDocFileSuite(
         '../doc/build-notification.txt',
         setUp=builddmasterSetUp,