Rev 4670: Launchpad urls can now be resolved from behind proxies in http://bazaar.launchpad.net/~vila/bzr/2.1.0-integration/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Mon Nov 2 15:32:20 GMT 2009
At http://bazaar.launchpad.net/~vila/bzr/2.1.0-integration/
------------------------------------------------------------
revno: 4670 [merge]
revision-id: v.ladeuil+lp at free.fr-20091102153216-s59m2ws5yyxguaa2
parent: pqm at pqm.ubuntu.com-20091031025119-p9o49k7xb50npphw
parent: v.ladeuil+lp at free.fr-20091030210237-y3va20lmppu1nbzp
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 2.1.0
timestamp: Mon 2009-11-02 16:32:16 +0100
message:
Launchpad urls can now be resolved from behind proxies
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-10-30 16:09:06 +0000
+++ b/NEWS 2009-11-02 15:32:16 +0000
@@ -31,6 +31,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)
+
* TreeTransform.adjust_path updates the limbo paths of descendants of adjusted
files. (Aaron Bentley)
=== 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