Rev 4673: Bring in 2.1.0b2 @ 4670 resolve NEWS in http://bazaar.launchpad.net/~jameinel/bzr/2.1.0b2-471193-st-and-chk-map

John Arbash Meinel john at arbash-meinel.com
Mon Nov 2 18:24:18 GMT 2009


At http://bazaar.launchpad.net/~jameinel/bzr/2.1.0b2-471193-st-and-chk-map

------------------------------------------------------------
revno: 4673 [merge]
revision-id: john at arbash-meinel.com-20091102182409-ncn8xi1a8amelaek
parent: john at arbash-meinel.com-20091102173939-ygeujjd6rfp5kais
parent: pqm at pqm.ubuntu.com-20091102171325-r6xp2p06u8tvamlp
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1.0b2-471193-st-and-chk-map
timestamp: Mon 2009-11-02 12:24:09 -0600
message:
  Bring in 2.1.0b2 @ 4670 resolve NEWS
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/plugins/launchpad/__init__.py __init__.py-20060315182712-2d5feebd2a1032dc
  bzrlib/plugins/launchpad/lp_registration.py lp_registration.py-20060315190948-daa617eafe3a8d48
  bzrlib/plugins/launchpad/test_lp_directory.py test_lp_indirect.py-20070126002743-oyle362tzv9cd8mi-1
  bzrlib/tests/test_http.py      testhttp.py-20051018020158-b2eef6e867c514d9
  bzrlib/transport/http/_urllib2_wrappers.py _urllib2_wrappers.py-20060913231729-ha9ugi48ktx481ao-1
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2009-11-02 17:15:20 +0000
+++ b/NEWS	2009-11-02 18:24:09 +0000
@@ -16,9 +16,10 @@
 
 Key highlights in this release are: improved handling of
 failures-during-cleanup for commit, fixing a long-standing bug with
-``bzr+http`` and shared repositories, and a new StaticTuple datatype,
-allowing us to reduce memory consumption (50%) and garbage collector
-overhead (40% faster) for many operations.
+``bzr+http`` and shared repositories, all ``lp:`` urls to be resolved
+behind proxies, and a new StaticTuple datatype, allowing us to reduce
+memory consumption (50%) and garbage collector overhead (40% faster) for
+many operations.
 
 Bug Fixes
 *********
@@ -31,6 +32,9 @@
   they do occur.  This fixes some causes of ``TooManyConcurrentRequests``
   and similar errors.  (Andrew Bennetts, #429747, #243391)
 
+* Launchpad urls can now be resolved from behind proxies.
+  (Gordon Tyler, Vincent Ladeuil, #198920)
+
 * Reduce the strictness for StaticTuple, instead add a debug flag
   ``-Dstatic_tuple`` which will change apis to be strict and raise errors.
   This way, most users won't see failures, but developers can improve

=== modified file 'bzrlib/plugins/launchpad/__init__.py'
--- a/bzrlib/plugins/launchpad/__init__.py	2009-07-06 13:00:23 +0000
+++ b/bzrlib/plugins/launchpad/__init__.py	2009-10-30 14:44:52 +0000
@@ -262,30 +262,19 @@
 _register_directory()
 
 
-def test_suite():
-    """Called by bzrlib to fetch tests for this plugin"""
-    from unittest import TestSuite, TestLoader
-    from bzrlib.plugins.launchpad import (
-        test_account,
-        test_lp_directory,
-        test_lp_login,
-        test_lp_open,
-        test_lp_service,
-        test_register,
-        )
+def load_tests(basic_tests, module, loader):
+    testmod_names = [
+        'test_account',
+        'test_register',
+        'test_lp_directory',
+        'test_lp_login',
+        'test_lp_open',
+        'test_lp_service',
+        ]
+    basic_tests.addTest(loader.loadTestsFromModuleNames(
+            ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))
+    return basic_tests
 
-    loader = TestLoader()
-    suite = TestSuite()
-    for module in [
-        test_account,
-        test_register,
-        test_lp_directory,
-        test_lp_login,
-        test_lp_open,
-        test_lp_service,
-        ]:
-        suite.addTests(loader.loadTestsFromModule(module))
-    return suite
 
 _launchpad_help = """Integration with Launchpad.net
 

=== modified file 'bzrlib/plugins/launchpad/lp_registration.py'
--- a/bzrlib/plugins/launchpad/lp_registration.py	2009-07-04 16:22:16 +0000
+++ b/bzrlib/plugins/launchpad/lp_registration.py	2009-10-30 21:02:37 +0000
@@ -31,6 +31,7 @@
     errors,
     __version__ as _bzrlib_version,
     )
+from bzrlib.transport.http import _urllib2_wrappers
 
 # for testing, do
 '''
@@ -53,6 +54,29 @@
         errors.BzrError.__init__(self, url=url)
 
 
+class XMLRPCTransport(xmlrpclib.Transport):
+
+    def __init__(self, scheme, use_datetime=0):
+        xmlrpclib.Transport.__init__(self, use_datetime=use_datetime)
+        self._scheme = scheme
+        self._opener = _urllib2_wrappers.Opener()
+        self.verbose = 0
+
+    def request(self, host, handler, request_body, verbose=0):
+        self.verbose = verbose
+        url = self._scheme + "://" + host + handler
+        request = _urllib2_wrappers.Request("POST", url, request_body)
+        # FIXME: _urllib2_wrappers will override user-agent with its own
+        # request.add_header("User-Agent", self.user_agent)
+        request.add_header("Content-Type", "text/xml")
+
+        response = self._opener.open(request)
+        if response.code != 200:
+            raise xmlrpclib.ProtocolError(host + handler, response.code,
+                                          response.msg, response.info())
+        return self.parse_response(response)
+
+
 class LaunchpadService(object):
     """A service to talk to Launchpad via XMLRPC.
 
@@ -90,10 +114,7 @@
         self._lp_instance = lp_instance
         if transport is None:
             uri_type = urllib.splittype(self.service_url)[0]
-            if uri_type == 'https':
-                transport = xmlrpclib.SafeTransport()
-            else:
-                transport = xmlrpclib.Transport()
+            transport = XMLRPCTransport(uri_type)
             transport.user_agent = 'bzr/%s (xmlrpclib/%s)' \
                     % (_bzrlib_version, xmlrpclib.__version__)
         self.transport = transport

=== modified file 'bzrlib/plugins/launchpad/test_lp_directory.py'
--- a/bzrlib/plugins/launchpad/test_lp_directory.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/plugins/launchpad/test_lp_directory.py	2009-10-30 21:02:37 +0000
@@ -16,10 +16,12 @@
 
 """Tests for directory lookup through Launchpad.net"""
 
+import os
 import xmlrpclib
 
 from bzrlib import (
     errors,
+    tests,
     )
 from bzrlib.branch import Branch
 from bzrlib.directory_service import directories
@@ -28,10 +30,38 @@
     TestCaseWithMemoryTransport
 )
 from bzrlib.transport import get_transport
-from bzrlib.plugins.launchpad import _register_directory
+from bzrlib.plugins.launchpad import (
+    _register_directory,
+    lp_registration,
+    )
 from bzrlib.plugins.launchpad.lp_directory import (
     LaunchpadDirectory)
 from bzrlib.plugins.launchpad.account import get_lp_login
+from bzrlib.tests import (
+    http_server,
+    http_utils,
+    )
+
+
+def load_tests(standard_tests, module, loader):
+    result = loader.suiteClass()
+    t_tests, remaining_tests = tests.split_suite_by_condition(
+        standard_tests, tests.condition_isinstance((
+                TestXMLRPCTransport,
+                )))
+    transport_scenarios = [
+        ('http', dict(server_class=PreCannedHTTPServer,)),
+        ]
+    if tests.HTTPSServerFeature.available():
+        transport_scenarios.append(
+            ('https', dict(server_class=PreCannedHTTPSServer,)),
+            )
+    tests.multiply_tests(t_tests, transport_scenarios, result)
+
+    # No parametrization for the remaining tests
+    result.addTests(remaining_tests)
+
+    return result
 
 
 class FakeResolveFactory(object):
@@ -190,3 +220,116 @@
         transport = get_transport('lp:///apt')
         branch = Branch.open_from_transport(transport)
         self.assertEqual(target_branch.base, branch.base)
+
+
+class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
+    """Request handler for a unique and pre-defined request.
+
+    The only thing we care about here is that we receive a connection. But
+    since we want to dialog with a real http client, we have to send it correct
+    responses.
+
+    We expect to receive a *single* request nothing more (and we won't even
+    check what request it is), the tests will recognize us from our response.
+    """
+
+    def handle_one_request(self):
+        tcs = self.server.test_case_server
+        requestline = self.rfile.readline()
+        headers = self.MessageClass(self.rfile, 0)
+        if requestline.startswith('POST'):
+            # The body should be a single line (or we don't know where it ends
+            # and we don't want to issue a blocking read)
+            body = self.rfile.readline()
+
+        self.wfile.write(tcs.canned_response)
+
+
+class PreCannedServerMixin(object):
+
+    def __init__(self):
+        super(PreCannedServerMixin, self).__init__(
+            request_handler=PredefinedRequestHandler)
+        # Bytes read and written by the server
+        self.bytes_read = 0
+        self.bytes_written = 0
+        self.canned_response = None
+
+
+class PreCannedHTTPServer(PreCannedServerMixin, http_server.HttpServer):
+    pass
+
+
+if tests.HTTPSServerFeature.available():
+    from bzrlib.tests import https_server
+    class PreCannedHTTPSServer(PreCannedServerMixin, https_server.HTTPSServer):
+        pass
+
+
+class TestXMLRPCTransport(tests.TestCase):
+
+    # set by load_tests
+    server_class = None
+
+    def setUp(self):
+        tests.TestCase.setUp(self)
+        self.server = self.server_class()
+        self.server.setUp()
+        # Ensure we don't clobber env
+        self._captureVar('BZR_LP_XMLRPC_URL', None)
+
+    def tearDown(self):
+        self.server.tearDown()
+        tests.TestCase.tearDown(self)
+
+    def set_canned_response(self, server, path):
+        response_format = '''HTTP/1.1 200 OK\r
+Date: Tue, 11 Jul 2006 04:32:56 GMT\r
+Server: Apache/2.0.54 (Fedora)\r
+Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
+ETag: "56691-23-38e9ae00"\r
+Accept-Ranges: bytes\r
+Content-Length: %(length)d\r
+Connection: close\r
+Content-Type: text/plain; charset=UTF-8\r
+\r
+<?xml version='1.0'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>urls</name>
+<value><array><data>
+<value><string>bzr+ssh://bazaar.launchpad.net/%(path)s</string></value>
+<value><string>http://bazaar.launchpad.net/%(path)s</string></value>
+</data></array></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
+'''
+        length = 334 + 2 * len(path)
+        server.canned_response = response_format % dict(length=length,
+                                                        path=path)
+
+    def do_request(self, server_url):
+        os.environ['BZR_LP_XMLRPC_URL'] = self.server.get_url()
+        service = lp_registration.LaunchpadService()
+        resolve = lp_registration.ResolveLaunchpadPathRequest('bzr')
+        result = resolve.submit(service)
+        return result
+
+    def test_direct_request(self):
+        self.set_canned_response(self.server, '~bzr-pqm/bzr/bzr.dev')
+        result = self.do_request(self.server.get_url())
+        urls = result.get('urls', None)
+        self.assertIsNot(None, urls)
+        self.assertEquals(
+            ['bzr+ssh://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev',
+             'http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev'],
+            urls)
+    # FIXME: we need to test with a real proxy, I can't find a way so simulate
+    # CONNECT without leaving one server hanging the test :-/ Since that maybe
+    # related to the leaking tests problems, I'll punt for now -- vila 20091030

=== modified file 'bzrlib/tests/test_http.py'
--- a/bzrlib/tests/test_http.py	2009-09-17 11:54:41 +0000
+++ b/bzrlib/tests/test_http.py	2009-10-30 09:34:50 +0000
@@ -1956,7 +1956,7 @@
         pass
 
 
-class TestActivity(tests.TestCase):
+class TestActivityMixin(object):
     """Test socket activity reporting.
 
     We use a special purpose server to control the bytes sent and received and
@@ -2100,3 +2100,57 @@
         code, f = t._post('abc def end-of-body\n')
         self.assertEqual('lalala whatever as long as itsssss\n', f.read())
         self.assertActivitiesMatch()
+
+
+class TestActivity(tests.TestCase, TestActivityMixin):
+
+    def setUp(self):
+        tests.TestCase.setUp(self)
+        self.server = self._activity_server(self._protocol_version)
+        self.server.setUp()
+        self.activities = {}
+        def report_activity(t, bytes, direction):
+            count = self.activities.get(direction, 0)
+            count += bytes
+            self.activities[direction] = count
+
+        # We override at class level because constructors may propagate the
+        # bound method and render instance overriding ineffective (an
+        # alternative would be to define a specific ui factory instead...)
+        self.orig_report_activity = self._transport._report_activity
+        self._transport._report_activity = report_activity
+
+    def tearDown(self):
+        self._transport._report_activity = self.orig_report_activity
+        self.server.tearDown()
+        tests.TestCase.tearDown(self)
+
+
+class TestNoReportActivity(tests.TestCase, TestActivityMixin):
+
+    def setUp(self):
+        tests.TestCase.setUp(self)
+        # Unlike TestActivity, we are really testing ReportingFileSocket and
+        # ReportingSocket, so we don't need all the parametrization. Since
+        # ReportingFileSocket and ReportingSocket are wrappers, it's easier to
+        # test them through their use by the transport than directly (that's a
+        # bit less clean but far more simpler and effective).
+        self.server = ActivityHTTPServer('HTTP/1.1')
+        self._transport=_urllib.HttpTransport_urllib
+
+        self.server.setUp()
+
+        # We override at class level because constructors may propagate the
+        # bound method and render instance overriding ineffective (an
+        # alternative would be to define a specific ui factory instead...)
+        self.orig_report_activity = self._transport._report_activity
+        self._transport._report_activity = None
+
+    def tearDown(self):
+        self._transport._report_activity = self.orig_report_activity
+        self.server.tearDown()
+        tests.TestCase.tearDown(self)
+
+    def assertActivitiesMatch(self):
+        # Nothing to check here
+        pass

=== modified file 'bzrlib/transport/http/_urllib2_wrappers.py'
--- a/bzrlib/transport/http/_urllib2_wrappers.py	2009-08-19 16:33:39 +0000
+++ b/bzrlib/transport/http/_urllib2_wrappers.py	2009-10-30 21:02:37 +0000
@@ -80,10 +80,13 @@
         self.filesock = filesock
         self._report_activity = report_activity
 
+    def report_activity(self, size, direction):
+        if self._report_activity:
+            self._report_activity(size, direction)
 
     def read(self, size=1):
         s = self.filesock.read(size)
-        self._report_activity(len(s), 'read')
+        self.report_activity(len(s), 'read')
         return s
 
     def readline(self):
@@ -93,7 +96,7 @@
         #  don't *need* the size parameter we'll stay with readline(self)
         #  --  vila 20090209
         s = self.filesock.readline()
-        self._report_activity(len(s), 'read')
+        self.report_activity(len(s), 'read')
         return s
 
     def __getattr__(self, name):
@@ -106,13 +109,17 @@
         self.sock = sock
         self._report_activity = report_activity
 
+    def report_activity(self, size, direction):
+        if self._report_activity:
+            self._report_activity(size, direction)
+
     def sendall(self, s, *args):
         self.sock.sendall(s, *args)
-        self._report_activity(len(s), 'write')
+        self.report_activity(len(s), 'write')
 
     def recv(self, *args):
         s = self.sock.recv(*args)
-        self._report_activity(len(s), 'read')
+        self.report_activity(len(s), 'read')
         return s
 
     def makefile(self, mode='r', bufsize=-1):
@@ -219,8 +226,7 @@
     # we want to warn. But not below a given thresold.
     _range_warning_thresold = 1024 * 1024
 
-    def __init__(self,
-                 report_activity=None):
+    def __init__(self, report_activity=None):
         self._response = None
         self._report_activity = report_activity
         self._ranges_received_whole_file = None
@@ -360,7 +366,13 @@
 
     def set_proxy(self, proxy, type):
         """Set the proxy and remember the proxied host."""
-        self.proxied_host = self.get_host()
+        # We need to set the default port ourselves way before it gets set
+        # in the HTTP[S]Connection object at build time.
+        if self.type == 'https':
+            conn_class = HTTPSConnection
+        else:
+            conn_class = HTTPConnection
+        self.proxied_host = '%s:%s' % (self.get_host(), conn_class.default_port)
         urllib2.Request.set_proxy(self, proxy, type)
 
 



More information about the bazaar-commits mailing list