← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jml/launchpad/zeca-is-keyserver into lp:launchpad

 

Jonathan Lange has proposed merging lp:~jml/launchpad/zeca-is-keyserver into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jml/launchpad/zeca-is-keyserver/+merge/50166

You might know about 'zeca'. It's a test key server that lives in our tree and gets used a reasonable amount by soyuz tests.

This branch moves it from canonical.zeca to lp.testing.keyserver, and updates quite a lot of code to no longer use the word 'zeca' to refer to this test key server.

Along the way, I made several cleanups:
 * Various flakes & copyright bumps
 * Added a DocTestMatches matcher that uses our standard flags
 * Restructured the keyserver package so that 'harness' (the whole point) is not kept in tests but is instead promoted
 * Refactored the way it arranges the web resource hierarchy so the resources themselves are complete
 * Changed some doctests to be Python tests, and made them slightly more unit-y

-- 
https://code.launchpad.net/~jml/launchpad/zeca-is-keyserver/+merge/50166
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jml/launchpad/zeca-is-keyserver into lp:launchpad.
=== modified file 'Makefile'
--- Makefile	2011-02-05 06:11:48 +0000
+++ Makefile	2011-02-17 15:11:53 +0000
@@ -394,7 +394,7 @@
 			  /var/tmp/mailman-xmlrpc.test \
 			  /var/tmp/ppa \
 			  /var/tmp/ppa.test \
-			  /var/tmp/zeca
+			  /var/tmp/testkeyserver
 	# /var/tmp/launchpad_mailqueue is created read-only on ec2test
 	# instances.
 	if [ -w /var/tmp/launchpad_mailqueue ]; then $(RM) -rf /var/tmp/launchpad_mailqueue; fi

=== modified file 'configs/testrunner/launchpad-lazr.conf'
--- configs/testrunner/launchpad-lazr.conf	2010-09-17 09:16:27 +0000
+++ configs/testrunner/launchpad-lazr.conf	2011-02-17 15:11:53 +0000
@@ -242,5 +242,5 @@
 [vhosts]
 use_https: False
 
-[zeca]
-root: /var/tmp/zeca.test
+[testkeyserver]
+root: /var/tmp/testkeyserver.test

=== modified file 'lib/canonical/config/schema-lazr.conf'
--- lib/canonical/config/schema-lazr.conf	2011-02-03 03:49:36 +0000
+++ lib/canonical/config/schema-lazr.conf	2011-02-17 15:11:53 +0000
@@ -2091,13 +2091,12 @@
 debug_log: /var/tmp/windmill-testrunner.log
 
 
-# Stubed Key server for test proposes, it's able to server
-# in SKS format, a restricted set of keys. (fixed address at
-# localhost:11371)
-[zeca]
+# Stubed Key server for test proposes, it's able to serve
+# in SKS format, a restricted set of keys.
+[testkeyserver]
 # Directory to be created to store the pre-installed key-files
 # datatype: string
-root: /var/tmp/zeca
+root: /var/tmp/testkeyserver
 
 
 # Configuration specific for code that is running in the Zopeless

=== modified file 'lib/canonical/launchpad/doc/gpghandler.txt'
--- lib/canonical/launchpad/doc/gpghandler.txt	2010-10-19 18:44:31 +0000
+++ lib/canonical/launchpad/doc/gpghandler.txt	2011-02-17 15:11:53 +0000
@@ -288,10 +288,10 @@
 IGPGHandler also allow callsites to upload the public part of a local
 key to the configuration keyserver.
 
-We will setup and use the test-keyserver (zeca).
+We will set up and use the test-keyserver.
 
-    >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-    >>> z = ZecaTestSetup()
+    >>> from lp.testing.keyserver import KeyServerTac
+    >>> z = KeyServerTac()
     >>> z.setUp()
 
 Upload the just-generated key to the keyserver so that we can reset
@@ -323,7 +323,7 @@
 
     >>> gpghandler.uploadPublicKey(new_key.fingerprint)
 
-Let's shut zeca down.
+Let's shut the test keyserver down.
 
     >>> z.tearDown()
 

=== modified file 'lib/canonical/launchpad/doc/logintoken-pages.txt'
--- lib/canonical/launchpad/doc/logintoken-pages.txt	2010-10-18 22:24:59 +0000
+++ lib/canonical/launchpad/doc/logintoken-pages.txt	2011-02-17 15:11:53 +0000
@@ -40,8 +40,8 @@
     ...     fingerprint='A419AE861E88BC9E04B9C26FBA2B9389DFD20543')
 
     # Start our stub GPG keyserver so that the key can be fetched by the page.
-    >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-    >>> z = ZecaTestSetup()
+    >>> from lp.testing.keyserver import KeyServerTac
+    >>> z = KeyServerTac()
     >>> z.setUp()
 
     >>> request = LaunchpadTestRequest(

=== modified file 'lib/canonical/launchpad/ftests/gpgkeys/README'
--- lib/canonical/launchpad/ftests/gpgkeys/README	2006-08-10 22:42:32 +0000
+++ lib/canonical/launchpad/ftests/gpgkeys/README	2011-02-17 15:11:53 +0000
@@ -1,9 +1,9 @@
 
-Keys in lib/canonical/launchpad/ftests/gpgkeys should be symlinked to
-entries in lib/canonical/zeca/ftests/keys. There should be symlinks for
-each individual subkey ID; for instance, for a regular sign-and-encrypt
-key there will be a symlink for the main signing subkey and one for the
-encryption subkey.
+Keys in lib/canonical/launchpad/ftests/gpgkeys should be symlinked to entries
+in lib/lp/testing/keyserver/tests/keys. There should be symlinks for each
+individual subkey ID; for instance, for a regular sign-and-encrypt key there
+will be a symlink for the main signing subkey and one for the encryption
+subkey.
 
 Some information on the keys in this directory:
 

=== modified file 'lib/canonical/librarian/testing/server.py'
--- lib/canonical/librarian/testing/server.py	2011-01-19 03:36:08 +0000
+++ lib/canonical/librarian/testing/server.py	2011-02-17 15:11:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Fixture for the librarians."""
@@ -9,7 +9,6 @@
     'LibrarianServerFixture',
     ]
 
-import atexit
 import os
 import shutil
 import tempfile
@@ -216,7 +215,7 @@
     @property
     def logfile(self):
         # Store the log in the server root; if its wanted after a test, that
-        # test can use addDetail to grab the log and include it in its 
+        # test can use addDetail to grab the log and include it in its
         # error.
         try:
             return os.path.join(self.root, 'librarian.log')

=== modified file 'lib/lp/archivepublisher/tests/archive-signing.txt'
--- lib/lp/archivepublisher/tests/archive-signing.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/archivepublisher/tests/archive-signing.txt	2011-02-17 15:11:53 +0000
@@ -19,10 +19,10 @@
 top-level 'Release' file, named 'Release.gpg' and a ASCII-armoded
 export of the public GPG key (name 'key.gpg')
 
-We will setup and use the test-keyserver (zeca).
+We will set up and use the test-keyserver.
 
-    >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-    >>> z = ZecaTestSetup()
+    >>> from lp.testing.keyserver import KeyServerTac
+    >>> z = KeyServerTac()
     >>> z.setUp()
 
 
@@ -433,6 +433,6 @@
     >>> shutil.rmtree(config.personalpackagearchive.signing_keys_root)
     >>> shutil.rmtree(config.personalpackagearchive.root)
 
-Let's shut zeca down.
+Let's shut the test key server down.
 
     >>> z.tearDown()

=== modified file 'lib/lp/archivepublisher/tests/test_publisher.py'
--- lib/lp/archivepublisher/tests/test_publisher.py	2011-02-04 05:11:00 +0000
+++ lib/lp/archivepublisher/tests/test_publisher.py	2011-02-17 15:11:53 +0000
@@ -23,11 +23,8 @@
 from canonical.database.constants import UTC_NOW
 from canonical.launchpad.ftests.keys_for_tests import gpgkeysdir
 from canonical.launchpad.interfaces.gpghandler import IGPGHandler
-from canonical.zeca.ftests.harness import ZecaTestSetup
-from lp.archivepublisher.config import (
-    Config,
-    getPubConfig,
-    )
+from lp.testing.keyserver import KeyServerTac
+from lp.archivepublisher.config import getPubConfig
 from lp.archivepublisher.diskpool import DiskPool
 from lp.archivepublisher.interfaces.archivesigningkey import (
     IArchiveSigningKey,
@@ -1044,7 +1041,6 @@
         ppa.buildd_secret = "geheim"
 
         # Setup the publisher for it and publish its repository.
-        archive_publisher = getPublisher(ppa, [], self.logger)
         pubconf = getPubConfig(ppa)
         htaccess_path = os.path.join(pubconf.htaccessroot, ".htaccess")
         self.assertTrue(os.path.exists(htaccess_path))
@@ -1286,7 +1282,7 @@
         self.assertTrue(cprov.archive.signing_key is None)
 
         # Start the test keyserver, so the signing_key can be uploaded.
-        z = ZecaTestSetup()
+        z = KeyServerTac()
         z.setUp()
 
         # Set a signing key for Celso's PPA.

=== modified file 'lib/lp/registry/browser/tests/gpg-views.txt'
--- lib/lp/registry/browser/tests/gpg-views.txt	2010-10-09 16:36:22 +0000
+++ lib/lp/registry/browser/tests/gpg-views.txt	2011-02-17 15:11:53 +0000
@@ -7,8 +7,8 @@
 
 Set up the key server:
 
-  >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-  >>> z = ZecaTestSetup()
+  >>> from lp.testing.keyserver import KeyServerTac
+  >>> z = KeyServerTac()
   >>> z.setUp()
 
 Grab the sample user:

=== modified file 'lib/lp/registry/stories/gpg-coc/01-claimgpg.txt'
--- lib/lp/registry/stories/gpg-coc/01-claimgpg.txt	2010-11-06 12:50:22 +0000
+++ lib/lp/registry/stories/gpg-coc/01-claimgpg.txt	2011-02-17 15:11:53 +0000
@@ -4,12 +4,12 @@
 == Setup ==
 
     >>> import email
-    >>> from canonical.zeca.ftests.harness import ZecaTestSetup
+    >>> from lp.testing.keyserver import KeyServerTac
     >>> from lp.services.mail import stub
 
-Setup the stub KeyServer:
+Set up the stub KeyServer:
 
-    >>> z = ZecaTestSetup()
+    >>> z = KeyServerTac()
     >>> z.setUp()
 
 

=== modified file 'lib/lp/registry/stories/gpg-coc/11-handle-special-keys.txt'
--- lib/lp/registry/stories/gpg-coc/11-handle-special-keys.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/registry/stories/gpg-coc/11-handle-special-keys.txt	2011-02-17 15:11:53 +0000
@@ -2,10 +2,10 @@
 special: either invalid, broken, revoked, expired, or already imported.
 
   >>> import email
-  >>> from canonical.zeca.ftests.harness import ZecaTestSetup
+  >>> from lp.testing.keyserver import KeyServerTac
   >>> from lp.services.mail import stub
 
-  >>> z = ZecaTestSetup()
+  >>> z = KeyServerTac()
   >>> z.setUp()
 
   >>> sign_only   = "447D BF38 C4F9 C4ED 7522  46B7 7D88 9137 17B0 5A8F"
@@ -26,7 +26,7 @@
   ...
   ...has already been imported...
 
-Finally, kill zeca:
+Finally, kill the test key server:
 
   >>> z.tearDown()
 

=== modified file 'lib/lp/registry/stories/person/xx-person-editgpgkeys-invalid-key.txt'
--- lib/lp/registry/stories/person/xx-person-editgpgkeys-invalid-key.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/registry/stories/person/xx-person-editgpgkeys-invalid-key.txt	2011-02-17 15:11:53 +0000
@@ -6,11 +6,11 @@
   >>> from canonical.launchpad.interfaces.authtoken import LoginTokenType
   >>> from canonical.launchpad.ftests import login, logout, ANONYMOUS
   >>> from canonical.launchpad.interfaces.logintoken import ILoginTokenSet
-  >>> from canonical.zeca.ftests.harness import ZecaTestSetup
+  >>> from lp.testing.keyserver import KeyServerTac
   >>> from lp.registry.interfaces.person import IPersonSet
 
   >>> tokenset = getUtility(ILoginTokenSet)
-  >>> z = ZecaTestSetup()
+  >>> z = KeyServerTac()
   >>> z.setUp()
 
 The following keys are used in these tests:

=== modified file 'lib/lp/soyuz/doc/soyuz-set-of-uploads.txt'
--- lib/lp/soyuz/doc/soyuz-set-of-uploads.txt	2010-12-22 20:46:21 +0000
+++ lib/lp/soyuz/doc/soyuz-set-of-uploads.txt	2011-02-17 15:11:53 +0000
@@ -3,7 +3,7 @@
 This test will:
 
   * Pre-create the directory structure
-  * Turn on the zeca keyserver
+  * Turn on the test keyserver
   * Run process-upload.py
   * Check result
   * Mark packages as ACCEPTED
@@ -54,13 +54,13 @@
 database and services to receive it. Since we're using
 'sample.person@xxxxxxxxxxxxx' as our Changed-By address and his
 key has signed all the relevant uploads in the suite of uploads we're
-using, this essentially boils down to ensuring that zeca and the
+using, this essentially boils down to ensuring that test keyserver and the
 librarian are running and making sure that the key is attached to the
 relevant launchpad person.
 
-  >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-  >>> zeca = ZecaTestSetup()
-  >>> zeca.setUp()
+  >>> from lp.testing.keyserver import KeyServerTac
+  >>> keyserver = KeyServerTac()
+  >>> keyserver.setUp()
 
 Import public keyring into current LPDB.
 
@@ -757,5 +757,5 @@
   >>> shutil.rmtree("/var/tmp/archive/")
   >>> shutil.rmtree(temp_dir)
 
-  >>> zeca.tearDown()
+  >>> keyserver.tearDown()
 

=== modified file 'lib/lp/soyuz/doc/soyuz-upload.txt'
--- lib/lp/soyuz/doc/soyuz-upload.txt	2010-12-03 18:28:03 +0000
+++ lib/lp/soyuz/doc/soyuz-upload.txt	2011-02-17 15:11:53 +0000
@@ -10,7 +10,7 @@
   * Import gpg key for katie
   * Register gpg key for katie
   * Register the katie user in the right team
-  * Turn on the zeca keyserver
+  * Turn on the test keyserver
   * Include the non_free component in the database
   * Run process-upload.py
   * Check result
@@ -261,13 +261,13 @@
   ...                        active=True)
 
 
-Now we want to turn on the zeca key server to provide the key we
+Now we want to turn on the test key server to provide the key we
 just imported. Remember that process-upload.py is running as
 a different process.
 
-  >>> from canonical.zeca.ftests.harness import ZecaTestSetup
-  >>> zeca = ZecaTestSetup()
-  >>> zeca.setUp()
+  >>> from lp.testing.keyserver import KeyServerTac
+  >>> keyserver = KeyServerTac()
+  >>> keyserver.setUp()
 
 
 Include non-free in the database. This will be done by the
@@ -770,7 +770,7 @@
 Remove the test archive from filesystem.
 
   >>> shutil.rmtree("/var/tmp/archive/")
-  >>> zeca.tearDown()
+  >>> keyserver.tearDown()
 
 
 Feito! ;-)

=== renamed directory 'lib/canonical/zeca' => 'lib/lp/testing/keyserver'
=== modified file 'lib/lp/testing/keyserver/__init__.py'
--- lib/canonical/zeca/__init__.py	2009-06-25 05:39:50 +0000
+++ lib/lp/testing/keyserver/__init__.py	2011-02-17 15:11:53 +0000
@@ -1,6 +1,10 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the GNU
+# Affero General Public License version 3 (see the file LICENSE).
 
 # pylint: disable-msg=W0401,W0403
 
-from zeca import *
+__all__ = [
+    'KeyServerTac',
+    ]
+
+from lp.testing.keyserver.harness import KeyServerTac

=== renamed file 'lib/canonical/zeca/ftests/harness.py' => 'lib/lp/testing/keyserver/harness.py'
--- lib/canonical/zeca/ftests/harness.py	2010-09-28 06:04:27 +0000
+++ lib/lp/testing/keyserver/harness.py	2011-02-17 15:11:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -6,133 +6,42 @@
 import os
 import shutil
 
-import canonical
 from canonical.config import config
 from canonical.launchpad.daemons.tachandler import TacTestSetup
 
 
-keysdir = os.path.join(os.path.dirname(__file__), 'keys')
-
-
-class ZecaTestSetup(TacTestSetup):
-    r"""Setup a zeca for use by functional tests
-
-    >>> fixture = ZecaTestSetup()
-    >>> fixture.setUp()
-
-    Make sure the server is running
-
-    >>> root_url = 'http://%s:%d' % (
-    ...     config.gpghandler.host, config.gpghandler.port)
-
-    We have a hamless application root page
-
-    >>> from urllib import urlopen
-
-    >>> print urlopen(root_url).read()
-    Copyright 2004-2009 Canonical Ltd.
-    <BLANKLINE>
-
-    A key index lookup form via GET.
-
-    >>> print urlopen(
-    ...    '%s/pks/lookup?op=index&search=0xDFD20543' % root_url
-    ...    ).read()
-    <html>
-    ...
-    <title>Results for Key 0xDFD20543</title>
-    ...
-    pub  1024D/DFD20543 2005-04-13 Sample Person (revoked) &lt;sample.revoked@xxxxxxxxxxxxx&gt;
-    ...
-
-    A key content lookup form via GET.
-
-    >>> print urlopen(
-    ...    '%s/pks/lookup?op=get&'
-    ...    'search=0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543' % root_url
-    ...    ).read()
-    <html>
-    ...
-    <title>Results for Key 0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543</title>
-    ...
-    -----BEGIN PGP PUBLIC KEY BLOCK-----
-    Version: GnuPG v1.4.9 (GNU/Linux)
-    <BLANKLINE>
-    mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
-    ...
-
-    We can also request a key ID instead of a fingerprint, and it will glob
-    for the fingerprint.
-
-    >>> print urlopen(
-    ...    '%s/pks/lookup?op=get&'
-    ...    'search=0xDFD20543' % root_url
-    ...    ).read()
-    <html>
-    ...
-    <title>Results for Key 0xDFD20543</title>
-    ...
-    -----BEGIN PGP PUBLIC KEY BLOCK-----
-    Version: GnuPG v1.4.9 (GNU/Linux)
-    <BLANKLINE>
-    mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
-    ...
-
-    If we request a nonexistent key, we get a nice error.
-
-    >>> print urlopen(
-    ...    '%s/pks/lookup?op=get&'
-    ...    'search=0xDFD20544' % root_url
-    ...    ).read()
-    <html>
-    ...
-    <title>Results for Key 0xDFD20544</title>
-    ...
-    Key Not Found
-    ...
-
-    A key submit form via POST (see doc/gpghandler.txt for more information).
-
-    >>> print urlopen('%s/pks/add' % root_url).read()
-    <html>
-    ...
-    <title>Submit a key</title>
-    ...
-
-    >>> fixture.tearDown()
-
-    And again for luck
-
-    >>> fixture.setUp()
-
-    >>> print urlopen(root_url).readline()
-    Copyright 2004-2009 Canonical Ltd.
-    <BLANKLINE>
-
-    >>> fixture.tearDown()
-    """
+KEYS_DIR = os.path.join(os.path.dirname(__file__), 'tests/keys')
+
+
+class KeyServerTac(TacTestSetup):
+    """A test key server for use by functional tests."""
+
     def setUpRoot(self):
         """Recreate root directory and copy needed keys"""
         if os.path.isdir(self.root):
             shutil.rmtree(self.root)
-        shutil.copytree(keysdir, self.root)
+        shutil.copytree(KEYS_DIR, self.root)
 
     @property
     def root(self):
-        return config.zeca.root
+        return config.testkeyserver.root
 
     @property
     def tacfile(self):
-        return os.path.abspath(os.path.join(
-            os.path.dirname(canonical.__file__), os.pardir, os.pardir,
-            'daemons/zeca.tac'
-            ))
+        return os.path.abspath(
+            os.path.join(os.path.dirname(__file__), 'testkeyserver.tac'))
 
     @property
     def pidfile(self):
-        return os.path.join(self.root, 'zeca.pid')
+        return os.path.join(self.root, 'testkeyserver.pid')
 
     @property
     def logfile(self):
-        return os.path.join(self.root, 'zeca.log')
-
+        return os.path.join(self.root, 'testkeyserver.log')
+
+
+    @property
+    def url(self):
+        """The URL that the web server will be running on."""
+        return 'http://%s:%d' % (
+            config.gpghandler.host, config.gpghandler.port)

=== renamed file 'daemons/zeca.tac' => 'lib/lp/testing/keyserver/testkeyserver.tac'
--- daemons/zeca.tac	2010-10-20 18:43:29 +0000
+++ lib/lp/testing/keyserver/testkeyserver.tac	2011-02-17 15:11:53 +0000
@@ -2,33 +2,28 @@
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 # Twisted Application Configuration file.
-# Use with "twistd2.3 -y <file.tac>", e.g. "twistd -noy server.tac"
+# Use with "twistd -y <file.tac>", e.g. "twistd -noy server.tac"
 
-from twisted.application import service, internet, strports
+from twisted.application import service, strports
 from twisted.web import server
 
 from canonical.config import config
 from canonical.launchpad.daemons import readyservice
 from canonical.launchpad.scripts import execute_zcml_for_scripts
-from canonical.zeca import Zeca, KeyServer, LookUp, SubmitKey
+from lp.testing.keyserver.web import KeyServerResource
 
 # Needed for using IGPGHandler for processing key submit.
 execute_zcml_for_scripts()
 
-root = config.zeca.root
-
-application = service.Application('Zeca')
-zecaService = service.IServiceCollection(application)
+application = service.Application('testkeyserver')
+svc = service.IServiceCollection(application)
 
 # Service that announces when the daemon is ready
-readyservice.ReadyService().setServiceParent(zecaService)
-
-zeca = Zeca()
-keyserver = KeyServer()
-keyserver.putChild('lookup', LookUp(root))
-keyserver.putChild('add', SubmitKey(root))
-zeca.putChild('pks', keyserver)
-
-site = server.Site(zeca)
+readyservice.ReadyService().setServiceParent(svc)
+
+site = server.Site(KeyServerResource(config.testkeyserver.root))
 site.displayTracebacks = False
-strports.service('11371', site).setServiceParent(zecaService)
+
+# Run on the port that gpghandler is configured to hit.
+port = 'tcp:%s' % (config.gpghandler.port,)
+strports.service(port, site).setServiceParent(svc)

=== renamed directory 'lib/canonical/zeca/ftests' => 'lib/lp/testing/keyserver/tests'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0x33C0A61893A5DC5EB325B29E415A12CAC2F30234.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/ftpmaster@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/ftpmaster@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0x340CA3BB270E2716C9EE0B768E7EB7086C64A8C5.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/foo.bar@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/foo.bar@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0x447DBF38C4F9C4ED752246B77D88913717B05A8F.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/sign.only@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/sign.only@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0x84D205F03E1E67096CB54E262BE83793AACCD97C.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/revoked.key@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/revoked.key@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0x961F4EB829D7D304A77477822BC8401620687895.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/daniel.silverstone@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/daniel.silverstone@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/test@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/test@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0xC85826521A6EF6A6037BB3F79FF2583E681B6469.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/celso.providelo@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/celso.providelo@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/0xECA5B797586F2E27381A16CFDE6C9167046C6D63.get'
=== target changed u'../../../launchpad/ftests/gpgkeys/expired.key@xxxxxxxxxxxxxxxxx' => u'../../../../../canonical/launchpad/ftests/gpgkeys/expired.key@xxxxxxxxxxxxxxxxx'
=== modified symlink 'lib/lp/testing/keyserver/tests/keys/README'
=== target changed u'../../../launchpad/ftests/gpgkeys/README' => u'../../../../../canonical/launchpad/ftests/gpgkeys/README'
=== modified file 'lib/lp/testing/keyserver/tests/test_harness.py'
--- lib/canonical/zeca/ftests/test_harness.py	2010-07-14 14:11:15 +0000
+++ lib/lp/testing/keyserver/tests/test_harness.py	2011-02-17 15:11:53 +0000
@@ -1,13 +1,31 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
 
-import doctest
-
-from canonical.launchpad.testing.systemdocs import default_optionflags
-
-def test_suite():
-    return doctest.DocTestSuite(
-        'canonical.zeca.ftests.harness', optionflags=default_optionflags)
-
+from urllib import urlopen
+
+from canonical.config import config
+
+from lp.testing import TestCase
+from lp.testing.keyserver import KeyServerTac
+from lp.testing.keyserver.web import GREETING
+
+
+class TestKeyServerTac(TestCase):
+
+    def test_url(self):
+        # The url is the one that gpghandler is configured to hit.
+        fixture = KeyServerTac()
+        self.assertEqual(
+            'http://%s:%d' % (
+                config.gpghandler.host, config.gpghandler.port),
+            fixture.url)
+
+    def test_starts_properly(self):
+        # Make sure the tac starts properly and that we can load the page.
+        fixture = KeyServerTac()
+        fixture.setUp()
+        self.addCleanup(fixture.tearDown)
+        content = urlopen(fixture.url).readline()
+        self.assertEqual(GREETING, content)

=== modified file 'lib/lp/testing/keyserver/tests/test_locate_key.py'
--- lib/canonical/zeca/ftests/test_locate_key.py	2009-08-20 13:52:59 +0000
+++ lib/lp/testing/keyserver/tests/test_locate_key.py	2011-02-17 15:11:53 +0000
@@ -1,13 +1,13 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the GNU
+# Affero General Public License version 3 (see the file LICENSE).
 
-import unittest
 import os.path
 
-from canonical.zeca.zeca import locate_key
-
-
-class LocateKeyTestCase(unittest.TestCase):
+from lp.testing import TestCase
+from lp.testing.keyserver.web import locate_key
+
+
+class LocateKeyTestCase(TestCase):
     root = os.path.join(os.path.dirname(__file__), 'keys')
 
     def assertKeyFile(self, suffix, filename):
@@ -35,9 +35,3 @@
     def test_locate_key_no_match(self):
         self.assertKeyFile('0xDEADBEEF.get', None)
 
-
-def test_suite():
-    suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(LocateKeyTestCase))
-    return suite
-

=== added file 'lib/lp/testing/keyserver/tests/test_web.py'
--- lib/lp/testing/keyserver/tests/test_web.py	1970-01-01 00:00:00 +0000
+++ lib/lp/testing/keyserver/tests/test_web.py	2011-02-17 15:11:53 +0000
@@ -0,0 +1,132 @@
+# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for the web resources of the testkeyserver."""
+
+__metaclass__ = type
+
+import os
+import shutil
+
+from testtools.deferredruntest import AsynchronousDeferredRunTest
+
+from twisted.internet.endpoints import serverFromString
+from twisted.web.client import getPage
+from twisted.web.server import Site
+
+from lp.testing import TestCase
+from lp.testing.keyserver.harness import KEYS_DIR
+from lp.testing.keyserver.web import KeyServerResource
+from lp.testing.matchers import DocTestMatches
+
+
+class TestWebResources(TestCase):
+
+    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=2)
+
+    def setUpKeysDirectory(self):
+        path = self.makeTemporaryDirectory()
+        path = os.path.join(path, 'keys')
+        shutil.copytree(KEYS_DIR, path)
+        return path
+
+    def makeService(self):
+        """Run a test key server on whatever port we have available."""
+        from twisted.internet import reactor
+        resource = KeyServerResource(self.setUpKeysDirectory())
+        site = Site(resource)
+        endpoint = serverFromString(reactor, 'tcp:0')
+        return endpoint.listen(site)
+
+    def fetchResource(self, listening_port, path):
+        """GET the content at 'path' from the web server at 'listening_port'.
+        """
+        url = 'http://localhost:%s/%s' % (
+            listening_port.getHost().port,
+            path.lstrip('/'))
+        return getPage(url)
+
+    def getURL(self, path):
+        """Start a test key server and get the content at 'path'."""
+        d = self.makeService()
+        def service_started(port):
+            self.addCleanup(port.stopListening)
+            return self.fetchResource(port, path)
+        return d.addCallback(service_started)
+
+    def assertContentMatches(self, path, content):
+        """Assert that the key server content at 'path' matches 'content'."""
+        d = self.getURL(path)
+        return d.addCallback(self.assertThat, DocTestMatches(content))
+
+    def test_index_lookup(self):
+        # A key index lookup form via GET.
+        return self.assertContentMatches(
+            '/pks/lookup?op=index&search=0xDFD20543',
+            '''\
+<html>
+...
+<title>Results for Key 0xDFD20543</title>
+...
+pub  1024D/DFD20543 2005-04-13 Sample Person (revoked) &lt;sample.revoked@xxxxxxxxxxxxx&gt;
+...
+''')
+
+    def test_content_lookup(self):
+        # A key content lookup form via GET.
+        return self.assertContentMatches(
+            '/pks/lookup?op=get&'
+            'search=0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543',
+            '''\
+<html>
+...
+<title>Results for Key 0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543</title>
+...
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+<BLANKLINE>
+mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
+...
+''')
+
+    def test_lookup_key_id(self):
+        # We can also request a key ID instead of a fingerprint, and it will
+        # glob for the fingerprint.
+        return self.assertContentMatches(
+            '/pks/lookup?op=get&search=0xDFD20543',
+            '''\
+<html>
+...
+<title>Results for Key 0xDFD20543</title>
+...
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.9 (GNU/Linux)
+<BLANKLINE>
+mQGiBEJdmOcRBADkNJPTBuCIefBdRAhvWyD9SSVHh8GHQWS7l9sRLEsirQkKz1yB
+...
+''')
+
+    def test_nonexistent_key(self):
+        # If we request a nonexistent key, we get a nice error.
+        return self.assertContentMatches(
+            '/pks/lookup?op=get&search=0xDFD20544',
+            '''\
+<html>
+...
+<title>Results for Key 0xDFD20544</title>
+...
+Key Not Found
+...
+''')
+
+    def test_add_key(self):
+        # A key submit form via POST (see doc/gpghandler.txt for more
+        # information).
+        return self.assertContentMatches(
+            '/pks/add',
+            '''\
+<html>
+...
+<title>Submit a key</title>
+...
+''')

=== renamed file 'lib/canonical/zeca/zeca.py' => 'lib/lp/testing/keyserver/web.py'
--- lib/canonical/zeca/zeca.py	2009-08-20 13:52:29 +0000
+++ lib/lp/testing/keyserver/web.py	2011-02-17 15:11:53 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """GPG Key Information Server Prototype.
@@ -12,7 +12,7 @@
  - 'add': adds a key to the collection (does not update the index)
 
 It only depends on GPG for key submission; for retrieval and searching
-it just looks for files in the root (eg. /var/tmp/zeca). The files
+it just looks for files in the root (eg. /var/tmp/testkeyserver). The files
 are named like this:
 
 0x<keyid|fingerprint>.<operation>
@@ -24,16 +24,12 @@
 note: remove the lines containing 'sub' or 'secret' keys
 
 $ gpg --export -a cprov > 0x681B6469.get
-
 """
 
 __metaclass__ = type
 
 __all__ = [
-    'KeyServer',
-    'LookUp',
-    'SubmitKey',
-    'Zeca',
+    'KeyServerResource',
     ]
 
 import glob
@@ -45,8 +41,11 @@
 from zope.component import getUtility
 
 from canonical.launchpad.interfaces.gpghandler import (
-    GPGKeyNotFoundError, IGPGHandler, MoreThanOneGPGKeyFound,
-    SecretGPGKeyImportDetected)
+    GPGKeyNotFoundError,
+    IGPGHandler,
+    MoreThanOneGPGKeyFound,
+    SecretGPGKeyImportDetected,
+    )
 
 
 GREETING = 'Copyright 2004-2009 Canonical Ltd.\n'
@@ -79,23 +78,40 @@
     return path
 
 
-class Zeca(Resource):
+class _BaseResource(Resource):
+
     def getChild(self, name, request):
+        """Redirect trailing slash correctly."""
         if name == '':
             return self
         return Resource.getChild(
             self, name, request)
 
+
+class KeyServerResource(_BaseResource):
+    """Root resource for the test keyserver."""
+
+    def __init__(self, root):
+        _BaseResource.__init__(self)
+        self.putChild('pks', PksResource(root))
+
     def render_GET(self, request):
         return GREETING
 
 
-class KeyServer(Zeca):
+class PksResource(_BaseResource):
+
+    def __init__(self, root):
+        _BaseResource.__init__(self)
+        self.putChild('lookup', LookUp(root))
+        self.putChild('add', SubmitKey(root))
+
     def render_GET(self, request):
         return 'Welcome To Fake SKS service.\n'
 
 
 class LookUp(Resource):
+
     isLeaf = True
     permitted_actions = ['index', 'get']
 

=== modified file 'lib/lp/testing/matchers.py'
--- lib/lp/testing/matchers.py	2011-01-12 20:48:19 +0000
+++ lib/lp/testing/matchers.py	2011-02-17 15:11:53 +0000
@@ -4,6 +4,7 @@
 __metaclass__ = type
 __all__ = [
     'Contains',
+    'DocTestMatches',
     'DoesNotCorrectlyProvide',
     'DoesNotProvide',
     'HasQueryCount',
@@ -18,6 +19,7 @@
 from testtools.content_type import UTF8_TEXT
 from testtools.matchers import (
     Equals,
+    DocTestMatches as OriginalDocTestMatches,
     Matcher,
     Mismatch,
     MismatchesAll,
@@ -302,3 +304,12 @@
             return None
         else:
             return MismatchesAll(mismatches)
+
+
+def DocTestMatches(example):
+    """See if a string matches a doctest example.
+
+    Uses the default doctest flags used across Launchpad.
+    """
+    from canonical.launchpad.testing.systemdocs import default_optionflags
+    return OriginalDocTestMatches(example, default_optionflags)

=== modified file 'lp-sfood-packages'
--- lp-sfood-packages	2010-03-21 16:35:28 +0000
+++ lp-sfood-packages	2011-02-17 15:11:53 +0000
@@ -17,7 +17,6 @@
 lp/archivepublisher
 lp/app
 lp/answers
-canonical/zeca
 canonical/widgets
 canonical/tests
 canonical/testing

=== modified file 'utilities/start-dev-soyuz.sh'
--- utilities/start-dev-soyuz.sh	2010-03-10 11:52:19 +0000
+++ utilities/start-dev-soyuz.sh	2011-02-17 15:11:53 +0000
@@ -8,11 +8,11 @@
     bin/twistd \
         --logfile "/var/tmp/development-$1.log" \
         --pidfile "/var/tmp/development-$1.pid" \
-        -y "daemons/$1.tac"
+        -y "$2"
 }
 
-start_twistd zeca
-start_twistd buildd-manager
+start_twistd testkeyserver lib/lp/testing/keyserver/testkeyserver.tac
+start_twistd buildd-manager daemons/buildd-manager.tac
 
 echo "Starting poppy."
 mkdir -p /var/tmp/poppy