← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~mbp/launchpad/mbp-trivial into lp:launchpad

 

Martin Pool has proposed merging lp:~mbp/launchpad/mbp-trivial into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #615740 test_on_merge.py doesn't handle eintr
  https://bugs.launchpad.net/bugs/615740


This tweaks Jeroen and Benji's recent work in "Faster builds" so that the makefile dependencies are more precise, to avoid unnecessary rebuilds.
-- 
https://code.launchpad.net/~mbp/launchpad/mbp-trivial/+merge/41268
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~mbp/launchpad/mbp-trivial into lp:launchpad.
=== modified file 'Makefile'
--- Makefile	2010-11-02 01:34:05 +0000
+++ Makefile	2010-11-19 07:58:04 +0000
@@ -34,6 +34,9 @@
 # Do not add bin/buildout to this list.
 # It is impossible to get buildout to tell us all the files it would
 # build, since each egg's setup.py doesn't tell us that information.
+#
+# NB: It's important BUILDOUT_BIN only mentions things genuinely produced by
+# buildout.
 BUILDOUT_BIN = \
     $(PY) bin/apiindex bin/combine-css bin/fl-build-report \
     bin/fl-credential-ctl bin/fl-install-demo bin/fl-monitor-ctl \
@@ -45,6 +48,8 @@
     bin/start_librarian bin/stxdocs bin/tags bin/test bin/tracereport \
     bin/twistd bin/update-download-cache bin/windmill
 
+BUILDOUT_TEMPLATES = buildout-templates/_pythonpath.py.in
+
 # DO NOT ALTER : this should just build by default
 default: inplace
 
@@ -58,7 +63,7 @@
 hosted_branches: $(PY)
 	$(PY) ./utilities/make-dummy-hosted-branches
 
-$(API_INDEX): $(BZR_VERSION_INFO)
+$(API_INDEX): $(BZR_VERSION_INFO) $(PY)
 	mkdir -p $(APIDOC_DIR).tmp
 	LPCONFIG=$(LPCONFIG) $(PY) ./utilities/create-lp-wadl-and-apidoc.py --force "$(WADL_TEMPLATE)"
 	mv $(APIDOC_DIR).tmp $(APIDOC_DIR)
@@ -66,7 +71,7 @@
 apidoc: compile $(API_INDEX)
 
 # Run by PQM.
-check_merge: $(PY)
+check_merge: $(BUILDOUT_BIN)
 	[ `PYTHONPATH= bzr status -S database/schema/ | \
 		grep -v "\(^P\|pending\|security.cfg\|Makefile\|unautovacuumable\|_pythonpath.py\)" | wc -l` -eq 0 ]
 	${PY} lib/canonical/tests/test_no_conflict_marker.py
@@ -140,12 +145,14 @@
 	${SHHH} bin/sprite-util create-image
 
 jsbuild_lazr: bin/jsbuild
-	# We absolutely do not want to include the lazr.testing module and its
-	# jsTestDriver test harness modifications in the lazr.js and launchpad.js
-	# roll-up files.  They fiddle with built-in functions!  See Bug 482340.
-	${SHHH} bin/jsbuild $(JSFLAGS) -b $(LAZR_BUILT_JS_ROOT) -x testing/ -c $(LAZR_BUILT_JS_ROOT)/yui
+	# We absolutely do not want to include the lazr.testing module and
+	# its jsTestDriver test harness modifications in the lazr.js and
+	# launchpad.js roll-up files.  They fiddle with built-in functions!
+	# See Bug 482340.
+	${SHHH} bin/jsbuild $(JSFLAGS) -b $(LAZR_BUILT_JS_ROOT) -x testing/ \
+	-c $(LAZR_BUILT_JS_ROOT)/yui
 
-jsbuild: jsbuild_lazr bin/jsbuild bin/jssize
+jsbuild: jsbuild_lazr bin/jsbuild bin/jssize $(BUILDOUT_BIN)
 	${SHHH} bin/jsbuild \
 		$(JSFLAGS) \
 		-n launchpad \
@@ -177,30 +184,45 @@
 	find eggs -name '*.pyc' -exec rm {} \;
 
 # The download-cache dependency comes *before* eggs so that developers get the
-# warning before the eggs directory is made.  The target for the eggs directory
-# is only there for deployment convenience.
+# warning before the eggs directory is made.  The target for the eggs
+# directory is only there for deployment convenience.
 # Note that the buildout version must be maintained here and in versions.cfg
 # to make sure that the build does not go over the network.
+#
+# buildout won't touch files that would have the same contents, but for Make's
+# sake we need them to get fresh timestamps, so we touch them after building.
 bin/buildout: download-cache eggs
 	$(SHHH) PYTHONPATH= $(PYTHON) bootstrap.py\
 		--setup-source=ez_setup.py \
 		--download-base=download-cache/dist --eggs=eggs \
 		--version=1.5.1
+	touch --no-create $@
 
 # This target is used by LOSAs to prepare a build to be pushed out to
 # destination machines.  We only want eggs: they are the expensive bits,
 # and the other bits might run into problems like bug 575037.  This
 # target runs buildout, and then removes everything created except for
 # the eggs.
-build_eggs: $(BUILDOUT_BIN) clean_buildout
+build_eggs: $(BUILDOUT_BIN)
 
 # This builds bin/py and all the other bin files except bin/buildout.
 # Remove the target before calling buildout to ensure that buildout
 # updates the timestamp.
-$(BUILDOUT_BIN): bin/buildout versions.cfg $(BUILDOUT_CFG) setup.py
-	$(RM) $@
+buildout_bin: $(BUILDOUT_BIN)
+
+# buildout won't touch files that would have the same contents, but for Make's
+# sake we need them to get fresh timestamps, so we touch them after building.
+#
+# If we listed every target on the left-hand side, a parallel make would try
+# multiple copies of this rule to build them all.  Instead, we nominally build
+# just $(PY), and everything else is implicitly updated by that.
+$(PY): bin/buildout versions.cfg $(BUILDOUT_CFG) setup.py \
+		$(BUILDOUT_TEMPLATES)
 	$(SHHH) PYTHONPATH= ./bin/buildout \
                 configuration:instance_name=${LPCONFIG} -c $(BUILDOUT_CFG)
+	touch $@
+
+$(subst $(PY),,$(BUILDOUT_BIN)): $(PY)
 
 # bin/compile_templates is responsible for building all chameleon templates,
 # of which there is currently one, but of which many more are coming.
@@ -405,7 +427,8 @@
 	# We insert the absolute path to the branch-rewrite script
 	# into the Apache config as we copy the file into position.
 	sed -e 's,%BRANCH_REWRITE%,$(shell pwd)/scripts/branch-rewrite.py,' configs/development/local-launchpad-apache > /etc/apache2/sites-available/local-launchpad
-	cp configs/development/local-vostok-apache /etc/apache2/sites-available/local-vostok
+	cp configs/development/local-vostok-apache \
+		/etc/apache2/sites-available/local-vostok
 	touch /var/tmp/bazaar.launchpad.dev/rewrite.log
 	chown $(SUDO_UID):$(SUDO_GID) /var/tmp/bazaar.launchpad.dev/rewrite.log
 
@@ -430,8 +453,9 @@
 
 lp.sfood:
 	# Generate import dependency graph
-	sfood -i -u -I lib/sqlobject -I lib/schoolbell -I lib/devscripts -I lib/contrib \
-	-I lib/canonical/not-used lib/canonical lib/lp 2>/dev/null | grep -v contrib/ \
+	sfood -i -u -I lib/sqlobject -I lib/schoolbell -I lib/devscripts \
+	-I lib/contrib -I lib/canonical/not-used lib/canonical \
+	lib/lp 2>/dev/null | grep -v contrib/ \
 	| grep -v sqlobject | grep -v BeautifulSoup | grep -v psycopg \
 	| grep -v schoolbell > lp.sfood.tmp
 	mv lp.sfood.tmp lp.sfood
@@ -463,10 +487,10 @@
 		--docformat restructuredtext --verbose-about epytext-summary \
 		$(PYDOCTOR_OPTIONS)
 
-.PHONY: apidoc check tags TAGS zcmldocs realclean clean debug stop\
-	start run ftest_build ftest_inplace test_build test_inplace pagetests\
-	check check_merge \
-	schema default launchpad.pot check_merge_ui pull scan sync_branches\
-	reload-apache hosted_branches check_db_merge check_mailman check_config\
-	jsbuild jsbuild_lazr clean_js clean_buildout buildonce_eggs build_eggs\
-	sprite_css sprite_image css_combine compile check_schema pydoctor
+.PHONY: apidoc buildout_bin check tags TAGS zcmldocs realclean clean debug \
+	stop start run ftest_build ftest_inplace test_build test_inplace \
+	pagetests check check_merge schema default launchpad.pot \
+	check_merge_ui pull scan sync_branches reload-apache hosted_branches \
+	check_db_merge check_mailman check_config jsbuild jsbuild_lazr \
+	clean_js clean_buildout buildonce_eggs build_eggs sprite_css \
+	sprite_image css_combine compile check_schema pydoctor

=== modified file 'cronscripts/publishing/cron.publish-copy-archives'
--- cronscripts/publishing/cron.publish-copy-archives	2010-06-25 14:36:11 +0000
+++ cronscripts/publishing/cron.publish-copy-archives	2010-11-19 07:58:04 +0000
@@ -10,7 +10,6 @@
     exit 1
 fi
 
-set -x
 set -e
 set -u
 
@@ -20,24 +19,23 @@
 
 
 # Informational -- this *MUST* match the database.
-ARCHIVEROOT=/srv/launchpad.net/ubuntu-archive/ubuntu
+ARCHIVEROOT=/srv/launchpad.net/rebuild-test/ubuntu
 DISTSROOT=$ARCHIVEROOT/dists
 OVERRIDEROOT=$ARCHIVEROOT/../ubuntu-overrides
 INDICES=$ARCHIVEROOT/indices
 PRODUCTION_CONFIG=ftpmaster-publish
 
 if [ "$LPCONFIG" = "$PRODUCTION_CONFIG" ]; then
-    GNUPGHOME=/srv/launchpad.net/ubuntu-archive/gnupg-home
+    GNUPGHOME=/srv/launchpad.net/rebuild-test/gnupg-home
 else
     echo GPG keys will come from ~/.gnupg
     # GNUPGHOME does not need to be set, keys can come from ~/.gnupg.
 fi
 
 # Configuration options.
-LAUNCHPADROOT=/srv/launchpad.net/codelines/current
-LOCKFILE=/srv/launchpad.net/ubuntu-archive/cron.daily.lock
+LAUNCHPADROOT=/srv/launchpad.net/production/launchpad
+LOCKFILE=/srv/launchpad.net/rebuild-test/cron.daily.lock
 DISTRONAME=ubuntu
-TRACEFILE=$ARCHIVEROOT/project/trace/$(hostname --fqdn)
 
 # Manipulate the environment.
 export GNUPGHOME
@@ -64,20 +62,5 @@
 # Publish the packages to disk.
 publish-distro.py -v -v --copy-archive -d $DISTRONAME
 
-set +x
-
 echo Removing uncompressed Packages and Sources files
 find ${DISTSROOT} \( -name "Packages" -o -name "Sources" \) -exec rm "{}" \;
-
-# Copy in the indices.
-if [ "$LPCONFIG" = "$PRODUCTION_CONFIG" ]; then
-    echo Copying the indices into place.
-    rm -f $INDICES/override.*
-    cp $OVERRIDEROOT/override.* $INDICES
-fi
-
-# Timestamp our trace file to track when the last archive publisher run took
-# place.
-if [ "$LPCONFIG" = "$PRODUCTION_CONFIG" ]; then
-    date -u > "$TRACEFILE"
-fi

=== modified file 'lib/canonical/buildd/binarypackage.py'
--- lib/canonical/buildd/binarypackage.py	2010-07-13 09:13:41 +0000
+++ lib/canonical/buildd/binarypackage.py	2010-11-19 07:58:04 +0000
@@ -19,9 +19,7 @@
 class BuildLogRegexes:
     """Build log regexes for performing actions based on regexes, and extracting dependencies for auto dep-waits"""
     GIVENBACK = [
-        (" terminated by signal 4"),
         ("^E: There are problems and -y was used without --force-yes"),
-        ("^make.* Illegal instruction"),
         ]
     DEPFAIL = [
         ("(?P<pk>[\-+.\w]+)\(inst [^ ]+ ! >> wanted (?P<v>[\-.+\w:~]+)\)","\g<pk> (>> \g<v>)"),

=== modified file 'lib/canonical/buildd/buildrecipe'
--- lib/canonical/buildd/buildrecipe	2010-09-30 20:22:15 +0000
+++ lib/canonical/buildd/buildrecipe	2010-11-19 07:58:04 +0000
@@ -11,6 +11,7 @@
 import os
 import pwd
 import re
+from resource import RLIMIT_AS, setrlimit
 import socket
 from subprocess import call, Popen, PIPE
 import sys
@@ -206,6 +207,7 @@
 
 
 if __name__ == '__main__':
+    setrlimit(RLIMIT_AS, (1000000000, -1))
     builder = RecipeBuilder(*sys.argv[1:])
     if builder.buildTree() != 0:
         sys.exit(RETCODE_FAILURE_BUILD_TREE)

=== renamed file 'lib/canonical/launchpad/doc/emailaddress.txt.disabled' => 'lib/canonical/launchpad/doc/emailaddress.txt'
--- lib/canonical/launchpad/doc/emailaddress.txt.disabled	2009-08-13 19:03:36 +0000
+++ lib/canonical/launchpad/doc/emailaddress.txt	2010-11-19 07:58:04 +0000
@@ -1,4 +1,5 @@
-= Email Addresses =
+Email Addresses
+===============
 
 In Launchpad we use email addresses to uniquely identify a person. This is why
 email addresses must be unique.
@@ -22,7 +23,7 @@
 
 Email addresses provide both IEmailAddress and IHasOwner.
 
-    >>> from canonical.launchpad.interfaces.launchpad import IHasOwner
+    >>> from lp.registry.interfaces.role import IHasOwner
     >>> verifyObject(IEmailAddress, email)
     True
     >>> verifyObject(IHasOwner, email)
@@ -66,11 +67,12 @@
     [u'celso.providelo@xxxxxxxxxxxxx', u'colin.watson@xxxxxxxxxxxxxxx',
      u'daniel.silverstone@xxxxxxxxxxxxx', u'edgar@xxxxxxxxxxxxxxxx',
      u'foo.bar@xxxxxxxxxxxxx', u'jeff.waugh@xxxxxxxxxxxxxxx',
-     u'limi@xxxxxxxxx', u'mark@xxxxxxxxxxx', u'steve.alexander@xxxxxxxxxxxxxxx',
-     u'support@xxxxxxxxxx']
-
-
-== Deleting email addresses ==
+     u'limi@xxxxxxxxx', u'mark@xxxxxxxxxxx',
+     u'steve.alexander@xxxxxxxxxxxxxxx', u'support@xxxxxxxxxx']
+
+
+Deleting email addresses
+------------------------
 
 Email addresses may be deleted if they're not a person's preferred one
 or the address of a team's mailing list.

=== modified file 'lib/lp/app/javascript/tests/test_lp_collapsibles.html'
--- lib/lp/app/javascript/tests/test_lp_collapsibles.html	2010-07-26 13:42:32 +0000
+++ lib/lp/app/javascript/tests/test_lp_collapsibles.html	2010-11-19 07:58:04 +0000
@@ -4,14 +4,14 @@
   <title>Launchpad Collapsibles</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../../icing/yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../../icing/yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../test.css" />
+  <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../../icing/lazr/build/effects/effects.js"></script>
   <script type="text/javascript" src="../lp.js"></script>
 
   <!-- The test suite -->

=== modified file 'lib/lp/app/javascript/tests/test_lp_collapsibles.js'
--- lib/lp/app/javascript/tests/test_lp_collapsibles.js	2010-07-26 13:42:32 +0000
+++ lib/lp/app/javascript/tests/test_lp_collapsibles.js	2010-11-19 07:58:04 +0000
@@ -1,21 +1,21 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
 YUI({
-    base: '../../../icing/yui/',
+    base: '../../../../canonical/launchpad/icing/yui/',
     filter: 'raw',
     combine: false
     }).use('test', 'console', 'lp', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
-Y.Test.Runner.add(new Y.Test.Case({
+var suite = new Y.Test.Suite("Collapsibles Tests");
+suite.add(new Y.Test.Case({
     name: "activate_collapsibles",
 
     _should: {
-        error: {
+        fail: {
             test_toggle_collapsible_fails_on_wrapperless_collapsible: true,
             test_toggle_collapsible_fails_on_iconless_collapsible: true,
-            test_activate_collapsibles_handles_no_collapsibles: false
         }
     },
 
@@ -149,17 +149,16 @@
     test_toggle_collapsible_opens_collapsed_collapsible: function() {
         // Calling toggle_collapsible() on a collapsed collapsible will
         // toggle its state to open.
+        Y.lp.activate_collapsibles();
         var collapsible = this.container.one('.collapsible');
-        collapsible.addClass('collapsed');
+        var wrapper_div = collapsible.one('.collapseWrapper');
+        wrapper_div.addClass('lazr-closed');
 
-        Y.lp.activate_collapsibles();
         Y.lp.toggle_collapsible(collapsible);
         this.wait(function() {
-
             // The collapsible's wrapper div will now be open.
             var icon = collapsible.one('img');
-            var wrapper_div = collapsible.one('.collapseWrapper');
-            Assert.isTrue(wrapper_div.hasClass('lazr-open'));
+            Assert.isFalse(wrapper_div.hasClass('lazr-closed'));
             Assert.areNotEqual(
                 -1, icon.get('src').indexOf('/@@/treeExpanded'));
         }, 500);
@@ -321,6 +320,15 @@
     }
 }));
 
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    status_node = Y.Node.create(
+        '<p id="complete">Test status: complete</p>');
+    Y.get('body').appendChild(status_node);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
 var yui_console = new Y.Console({
     newestOnTop: false
 });

=== added directory 'lib/lp/app/windmill'
=== added file 'lib/lp/app/windmill/__init__.py'
=== added file 'lib/lp/app/windmill/testing.py'
--- lib/lp/app/windmill/testing.py	1970-01-01 00:00:00 +0000
+++ lib/lp/app/windmill/testing.py	2010-11-19 07:58:04 +0000
@@ -0,0 +1,21 @@
+# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Launchpad app specific testing infrastructure for Windmill."""
+
+__metaclass__ = type
+__all__ = [
+    'AppWindmillLayer',
+    ]
+
+
+from canonical.testing.layers import BaseWindmillLayer
+
+
+class AppWindmillLayer(BaseWindmillLayer):
+    """Layer for App Windmill tests."""
+
+    @classmethod
+    def setUp(cls):
+        cls.base_url = cls.appserver_root_url()
+        super(AppWindmillLayer, cls).setUp()

=== added directory 'lib/lp/app/windmill/tests'
=== added file 'lib/lp/app/windmill/tests/__init__.py'
=== added file 'lib/lp/app/windmill/tests/test_yuitests.py'
--- lib/lp/app/windmill/tests/test_yuitests.py	1970-01-01 00:00:00 +0000
+++ lib/lp/app/windmill/tests/test_yuitests.py	2010-11-19 07:58:04 +0000
@@ -0,0 +1,24 @@
+# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Run YUI.test tests."""
+
+__metaclass__ = type
+__all__ = []
+
+from lp.app.windmill.testing import AppWindmillLayer
+from lp.testing import (
+    build_yui_unittest_suite,
+    YUIUnitTestCase,
+    )
+
+
+class AppYUIUnitTestCase(YUIUnitTestCase):
+
+    layer = AppWindmillLayer
+    suite_name = 'AppYUIUnitTests'
+
+
+def test_suite():
+    app_testing_path = 'lp/app/javascript/tests'
+    return build_yui_unittest_suite(app_testing_path, AppYUIUnitTestCase)

=== modified file 'lib/lp/buildmaster/manager.py'
--- lib/lp/buildmaster/manager.py	2010-10-28 15:04:15 +0000
+++ lib/lp/buildmaster/manager.py	2010-11-19 07:58:04 +0000
@@ -151,10 +151,12 @@
         if failure.check(
             BuildSlaveFailure, CannotBuild, BuildBehaviorMismatch,
             CannotResumeHost, BuildDaemonError, CannotFetchFile):
-            self.logger.info("Scanning failed with: %s" % error_message)
+            self.logger.info("Scanning %s failed with: %s" % (
+                self.builder_name, error_message))
         else:
-            self.logger.info("Scanning failed with: %s\n%s" %
-                (failure.getErrorMessage(), failure.getTraceback()))
+            self.logger.info("Scanning %s failed with: %s\n%s" % (
+                self.builder_name, failure.getErrorMessage(),
+                failure.getTraceback()))
 
         # Decide if we need to terminate the job or fail the
         # builder.

=== modified file 'lib/lp/buildmaster/model/builder.py'
--- lib/lp/buildmaster/model/builder.py	2010-11-10 13:06:05 +0000
+++ lib/lp/buildmaster/model/builder.py	2010-11-19 07:58:04 +0000
@@ -8,6 +8,7 @@
 __all__ = [
     'Builder',
     'BuilderSet',
+    'ProxyWithConnectionTimeout',
     'rescueBuilderIfLost',
     'updateBuilderStatus',
     ]
@@ -99,6 +100,41 @@
     noisy = False
 
 
+class ProxyWithConnectionTimeout(xmlrpc.Proxy):
+    """Extend Twisted's Proxy to provide a configurable connection timeout."""
+
+    def __init__(self, url, user=None, password=None, allowNone=False,
+                 useDateTime=False, timeout=None):
+        xmlrpc.Proxy.__init__(
+            self, url, user, password, allowNone, useDateTime)
+        if timeout is None:
+            self.timeout = config.builddmaster.socket_timeout
+        else:
+            self.timeout = timeout
+
+    def callRemote(self, method, *args):
+        """Basically a carbon copy of the parent but passes the timeout
+        to connectTCP."""
+
+        def cancel(d):
+            factory.deferred = None
+            connector.disconnect()
+        factory = self.queryFactory(
+            self.path, self.host, method, self.user,
+            self.password, self.allowNone, args, cancel, self.useDateTime)
+        if self.secure:
+            from twisted.internet import ssl
+            connector = default_reactor.connectSSL(
+                self.host, self.port or 443, factory,
+                ssl.ClientContextFactory(),
+                timeout=self.timeout)
+        else:
+            connector = default_reactor.connectTCP(
+                self.host, self.port or 80, factory,
+                timeout=self.timeout)
+        return factory.deferred
+
+
 class BuilderSlave(object):
     """Add in a few useful methods for the XMLRPC slave.
 
@@ -141,7 +177,7 @@
         """
         rpc_url = urlappend(builder_url.encode('utf-8'), 'rpc')
         if proxy is None:
-            server_proxy = xmlrpc.Proxy(rpc_url, allowNone=True)
+            server_proxy = ProxyWithConnectionTimeout(rpc_url, allowNone=True)
             server_proxy.queryFactory = QuietQueryFactory
         else:
             server_proxy = proxy
@@ -213,7 +249,7 @@
         :param libraryfilealias: An `ILibraryFileAlias`.
         """
         url = libraryfilealias.http_url
-        logger.debug(
+        logger.info(
             "Asking builder on %s to ensure it has file %s (%s, %s)" % (
                 self._file_cache_url, libraryfilealias.filename, url,
                 libraryfilealias.content.sha1))
@@ -432,7 +468,7 @@
             return defer.fail(CannotResumeHost('Undefined vm_host.'))
 
         logger = self._getSlaveScannerLogger()
-        logger.debug("Resuming %s (%s)" % (self.name, self.url))
+        logger.info("Resuming %s (%s)" % (self.name, self.url))
 
         d = self.slave.resume()
         def got_resume_ok((stdout, stderr, returncode)):

=== modified file 'lib/lp/buildmaster/tests/test_builder.py'
--- lib/lp/buildmaster/tests/test_builder.py	2010-11-10 22:40:05 +0000
+++ lib/lp/buildmaster/tests/test_builder.py	2010-11-19 07:58:04 +0000
@@ -43,6 +43,10 @@
     )
 from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
 from lp.buildmaster.interfaces.builder import CannotResumeHost
+from lp.buildmaster.model.builder import (
+    BuilderSlave,
+    ProxyWithConnectionTimeout,
+    )
 from lp.buildmaster.model.buildfarmjobbehavior import IdleBuildBehavior
 from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.buildmaster.tests.mock_slaves import (
@@ -1059,6 +1063,56 @@
             self.slave.build(None, None, None, None, None))
 
 
+class TestSlaveConnectionTimeouts(TrialTestCase):
+    # Testing that we can override the default 30 second connection
+    # timeout.
+
+    layer = TwistedLayer
+
+    def setUp(self):
+        super(TestSlaveConnectionTimeouts, self).setUp()
+        self.slave_helper = SlaveTestHelpers()
+        self.slave_helper.setUp()
+        self.addCleanup(self.slave_helper.cleanUp)
+        self.clock = Clock()
+        self.proxy = ProxyWithConnectionTimeout("fake_url")
+        self.slave = self.slave_helper.getClientSlave(
+            reactor=self.clock, proxy=self.proxy)
+
+    def test_connection_timeout(self):
+        # The default timeout of 30 seconds should not cause a timeout,
+        # only the config value should.
+        timeout_config = """
+        [builddmaster]
+        socket_timeout: 180
+        """
+        config.push('timeout', timeout_config)
+        self.addCleanup(config.pop, 'timeout')
+
+        d = self.slave.echo()
+        # Advance past the 30 second timeout.  The real reactor will
+        # never call connectTCP() since we're not spinning it up.  This
+        # avoids "connection refused" errors and simulates an
+        # environment where the endpoint doesn't respond.
+        self.clock.advance(31)
+        self.assertFalse(d.called)
+
+        # Now advance past the real socket timeout and expect a
+        # Failure.
+
+        def got_timeout(failure):
+            self.assertIsInstance(failure.value, CancelledError)
+
+        d.addBoth(got_timeout)
+        self.clock.advance(config.builddmaster.socket_timeout + 1)
+        self.assertTrue(d.called)
+
+    def test_BuilderSlave_uses_ProxyWithConnectionTimeout(self):
+        # Make sure that BuilderSlaves use the custom proxy class.
+        slave = BuilderSlave.makeBuilderSlave("url", "host")
+        self.assertIsInstance(slave._server, ProxyWithConnectionTimeout)
+
+
 class TestSlaveWithLibrarian(TrialTestCase):
     """Tests that need more of Launchpad to run."""
 

=== modified file 'lib/lp/code/model/recipebuilder.py'
--- lib/lp/code/model/recipebuilder.py	2010-10-27 14:25:19 +0000
+++ lib/lp/code/model/recipebuilder.py	2010-11-19 07:58:04 +0000
@@ -122,6 +122,8 @@
         if chroot is None:
             raise CannotBuild("Unable to find a chroot for %s" %
                               distroarchseries.displayname)
+        logger.info(
+            "Sending chroot file for recipe build to %s" % self._builder.name)
         d = self._builder.slave.cacheFile(logger, chroot)
 
         def got_cache_file(ignored):
@@ -131,7 +133,7 @@
             buildid = "%s-%s" % (self.build.id, build_queue_id)
             cookie = self.buildfarmjob.generateSlaveBuildCookie()
             chroot_sha1 = chroot.content.sha1
-            logger.debug(
+            logger.info(
                 "Initiating build %s on %s" % (buildid, self._builder.url))
 
             return self._builder.slave.build(

=== modified file 'lib/lp/code/model/tests/test_recipebuilder.py'
--- lib/lp/code/model/tests/test_recipebuilder.py	2010-10-26 15:47:24 +0000
+++ lib/lp/code/model/tests/test_recipebuilder.py	2010-11-19 07:58:04 +0000
@@ -282,8 +282,13 @@
         d = defer.maybeDeferred(job.dispatchBuildToSlave, "someid", logger)
         def check_dispatch(ignored):
             logger.buffer.seek(0)
-            self.assertEquals(
-                "DEBUG: Initiating build 1-someid on http://fake:0000\n";,
+
+            self.assertEquals(
+                "INFO: Sending chroot file for recipe build to "
+                "bob-de-bouwer\n",
+                logger.buffer.readline())
+            self.assertEquals(
+                "INFO: Initiating build 1-someid on http://fake:0000\n";,
                 logger.buffer.readline())
             self.assertEquals(["ensurepresent", "build"],
                               [call[0] for call in slave.call_log])
@@ -293,7 +298,8 @@
             self.assertEquals(build_args[1], "sourcepackagerecipe")
             self.assertEquals(build_args[3], [])
             distroarchseries = job.build.distroseries.architectures[0]
-            self.assertEqual(build_args[4], job._extraBuildArgs(distroarchseries))
+            self.assertEqual(
+                build_args[4], job._extraBuildArgs(distroarchseries))
         return d.addCallback(check_dispatch)
 
     def test_dispatchBuildToSlave_nochroot(self):

=== modified file 'lib/lp/registry/javascript/tests/test_milestone_table.html'
--- lib/lp/registry/javascript/tests/test_milestone_table.html	2010-04-28 18:43:25 +0000
+++ lib/lp/registry/javascript/tests/test_milestone_table.html	2010-11-19 07:58:04 +0000
@@ -9,7 +9,7 @@
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../../canonical/launchpad/javascript/test.css" />
+  <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../milestonetable.js"></script>

=== modified file 'lib/lp/services/mailman/doc/postings.txt'
--- lib/lp/services/mailman/doc/postings.txt	2010-10-25 12:11:43 +0000
+++ lib/lp/services/mailman/doc/postings.txt	2010-11-19 07:58:04 +0000
@@ -177,25 +177,6 @@
     From: itest-one-...@xxxxxxxxxxxxxxxxxxx
     To: anne.person@xxxxxxxxxxx
     ...
-    Sender: itest-one-bounces+anne.person=example.com@xxxxxxxxxxxxxxxxxxx
-    Errors-To: itest-one-bounces+anne.person=example.com@xxxxxxxxxxxxxxxxxxx
-    ...
-    X-MailFrom: itest-one-bounces+anne.person=example.com@xxxxxxxxxxxxxxxxxxx
-    X-RcptTo: anne.person@xxxxxxxxxxx
-    <BLANKLINE>
-    Your request to the Itest-one mailing list
-    <BLANKLINE>
-        Posting of your message titled "An unsubscribed post"
-    <BLANKLINE>
-    has been rejected by the list moderator.  The moderator gave the
-    following reason for rejecting your request:
-    <BLANKLINE>
-    "[No reason given]"
-    <BLANKLINE>
-    Any questions or comments should be directed to the list administrator
-    at:
-    <BLANKLINE>
-        itest-one-owner@xxxxxxxxxxxxxxxxxxx
 
 Anne posts another message to the mailing list, but she is still not
 subscribed to it.  The team administrator deems this message to be spam and

=== modified file 'lib/lp/translations/windmill/tests/test_languages.py'
--- lib/lp/translations/windmill/tests/test_languages.py	2010-10-18 12:56:47 +0000
+++ lib/lp/translations/windmill/tests/test_languages.py	2010-11-19 07:58:04 +0000
@@ -7,6 +7,7 @@
 __all__ = []
 
 from canonical.launchpad.windmill.testing.constants import (
+    FOR_ELEMENT,
     PAGE_LOAD,
     SLEEP,
     )
@@ -61,7 +62,8 @@
         # "Not-matching" message is hidden and languages are visible.
         self.client.asserts.assertProperty(
             id=u'no_filter_matches',
-            validator='className|unseen')
+            validator='className|unseen',
+            timeout=FOR_ELEMENT)
         self._assert_languages_visible({
             u'German': True,
             u'Mende': True,


Follow ups