Rev 3120: Most refactoring regarding parameterization for urllib/pycurl and custom in file:///v/home/vila/src/bzr/bugs/175524/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Wed Dec 19 11:29:16 GMT 2007
At file:///v/home/vila/src/bzr/bugs/175524/
------------------------------------------------------------
revno: 3120
revision-id:v.ladeuil+lp at free.fr-20071219112912-fd3wdp4z3tmknf0v
parent: v.ladeuil+lp at free.fr-20071219093256-ibps16qrj0iji35v
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 175524
timestamp: Wed 2007-12-19 12:29:12 +0100
message:
Most refactoring regarding parameterization for urllib/pycurl and custom
request handlers done.
* bzrlib/tests/test_http_implementations.py:
Transfer more tests from test_http.py and dedicated request
handlers from http_utils.py.
* bzrlib/tests/test_http.py:
Transfer more tests to test_http_implementations.
* bzrlib/tests/http_utils.py:
Transfer to http_test_implementations.py all request hadlers that
exercise "bogus" behaviors since they are specific to some tests
and not expected to be reused.
modified:
bzrlib/tests/http_utils.py HTTPTestUtil.py-20050914180604-247d3aafb7a43343
bzrlib/tests/test_http.py testhttp.py-20051018020158-b2eef6e867c514d9
bzrlib/tests/test_http_implementations.py test_http_implementa-20071218210003-65nh81gglcfvurw6-1
-------------- next part --------------
=== modified file 'bzrlib/tests/http_utils.py'
--- a/bzrlib/tests/http_utils.py 2007-12-19 09:29:21 +0000
+++ b/bzrlib/tests/http_utils.py 2007-12-19 11:29:12 +0000
@@ -37,78 +37,6 @@
)
-class WallRequestHandler(TestingHTTPRequestHandler):
- """Whatever request comes in, close the connection"""
-
- def handle_one_request(self):
- """Handle a single HTTP request, by abruptly closing the connection"""
- self.close_connection = 1
-
-
-class BadStatusRequestHandler(TestingHTTPRequestHandler):
- """Whatever request comes in, returns a bad status"""
-
- def parse_request(self):
- """Fakes handling a single HTTP request, returns a bad status"""
- ignored = TestingHTTPRequestHandler.parse_request(self)
- try:
- self.send_response(0, "Bad status")
- self.end_headers()
- except socket.error, e:
- # We don't want to pollute the test results with
- # spurious server errors while test succeed. In our
- # case, it may occur that the test has already read
- # the 'Bad Status' and closed the socket while we are
- # still trying to send some headers... So the test is
- # ok, but if we raise the exception, the output is
- # dirty. So we don't raise, but we close the
- # connection, just to be safe :)
- spurious = [errno.EPIPE,
- errno.ECONNRESET,
- errno.ECONNABORTED,
- ]
- if (len(e.args) > 0) and (e.args[0] in spurious):
- self.close_connection = 1
- pass
- else:
- raise
- return False
-
-
-class InvalidStatusRequestHandler(TestingHTTPRequestHandler):
- """Whatever request comes in, returns am invalid status"""
-
- def parse_request(self):
- """Fakes handling a single HTTP request, returns a bad status"""
- ignored = TestingHTTPRequestHandler.parse_request(self)
- self.wfile.write("Invalid status line\r\n")
- return False
-
-
-class BadProtocolRequestHandler(TestingHTTPRequestHandler):
- """Whatever request comes in, returns a bad protocol version"""
-
- def parse_request(self):
- """Fakes handling a single HTTP request, returns a bad status"""
- ignored = TestingHTTPRequestHandler.parse_request(self)
- # Returns an invalid protocol version, but curl just
- # ignores it and those cannot be tested.
- self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
- 404,
- 'Look at my protocol version'))
- return False
-
-
-class ForbiddenRequestHandler(TestingHTTPRequestHandler):
- """Whatever request comes in, returns a 403 code"""
-
- def parse_request(self):
- """Handle a single HTTP request, by replying we cannot handle it"""
- ignored = TestingHTTPRequestHandler.parse_request(self)
- self.send_error(403)
- return False
-
-
class HTTPServerWithSmarts(HttpServer):
"""HTTPServerWithSmarts extends the HttpServer with POST methods that will
trigger a smart server to execute with a transport rooted at the rootdir of
@@ -151,65 +79,6 @@
self.wfile.write(out_buffer.getvalue())
-class LimitedRangeRequestHandler(TestingHTTPRequestHandler):
- """Errors out when range specifiers exceed the limit"""
-
- def get_multiple_ranges(self, file, file_size, ranges):
- """Refuses the multiple ranges request"""
- tcs = self.server.test_case_server
- if tcs.range_limit is not None and len(ranges) > tcs.range_limit:
- file.close()
- # Emulate apache behavior
- self.send_error(400, "Bad Request")
- return
- return TestingHTTPRequestHandler.get_multiple_ranges(self, file,
- file_size, ranges)
-
-
-class LimitedRangeHTTPServer(HttpServer):
- """An HttpServer erroring out on requests with too much range specifiers"""
-
- def __init__(self, request_handler=LimitedRangeRequestHandler,
- range_limit=None):
- HttpServer.__init__(self, request_handler)
- self.range_limit = range_limit
-
-
-class SingleRangeRequestHandler(TestingHTTPRequestHandler):
- """Always reply to range request as if they were single.
-
- Don't be explicit about it, just to annoy the clients.
- """
-
- def get_multiple_ranges(self, file, file_size, ranges):
- """Answer as if it was a single range request and ignores the rest"""
- (start, end) = ranges[0]
- return self.get_single_range(file, file_size, start, end)
-
-
-class SingleOnlyRangeRequestHandler(TestingHTTPRequestHandler):
- """Only reply to simple range requests, errors out on multiple"""
-
- def get_multiple_ranges(self, file, file_size, ranges):
- """Refuses the multiple ranges request"""
- if len(ranges) > 1:
- file.close()
- self.send_error(416, "Requested range not satisfiable")
- return
- (start, end) = ranges[0]
- return self.get_single_range(file, file_size, start, end)
-
-
-class NoRangeRequestHandler(TestingHTTPRequestHandler):
- """Ignore range requests without notice"""
-
- def do_GET(self):
- # Update the statistics
- self.server.test_case_server.GET_request_nb += 1
- # Just bypass the range handling done by TestingHTTPRequestHandler
- return SimpleHTTPRequestHandler.do_GET(self)
-
-
class TestCaseWithWebserver(TestCaseWithTransport):
"""A support class that provides readonly urls that are http://.
=== modified file 'bzrlib/tests/test_http.py'
--- a/bzrlib/tests/test_http.py 2007-12-19 09:29:21 +0000
+++ b/bzrlib/tests/test_http.py 2007-12-19 11:29:12 +0000
@@ -46,24 +46,15 @@
StringIOWrapper,
)
from bzrlib.tests.http_utils import (
- BadProtocolRequestHandler,
- BadStatusRequestHandler,
- ForbiddenRequestHandler,
HTTPBasicAuthServer,
HTTPDigestAuthServer,
HTTPServerRedirecting,
- InvalidStatusRequestHandler,
- LimitedRangeHTTPServer,
- NoRangeRequestHandler,
ProxyBasicAuthServer,
ProxyDigestAuthServer,
ProxyServer,
- SingleRangeRequestHandler,
- SingleOnlyRangeRequestHandler,
TestCaseWithRedirectedWebserver,
TestCaseWithTwoWebservers,
TestCaseWithWebserver,
- WallRequestHandler,
)
from bzrlib.transport import (
_CoalescedOffset,
@@ -170,11 +161,7 @@
f.credentials[0])
-class TestHttpUrls_pycurl(TestWithTransport_pycurl, tests.TestCase):
- """Test http urls with pycurl"""
-
- _server = http_server.HttpServer_PyCurl
- _qualified_prefix = 'http+pycurl'
+class TestHttps_pycurl(TestWithTransport_pycurl, tests.TestCase):
# TODO: This should really be moved into another pycurl
# specific test. When https tests will be implemented, take
@@ -209,16 +196,6 @@
self.assertRaises(errors.DependencyNotPresent, self._transport,
'https://launchpad.net')
-class TestHttpTransportRegistration(tests.TestCase):
- """Test registrations of various http implementations"""
-
- def test_http_registered(self):
- # urlllib should always be present
- t = get_transport('http+urllib://bzr.google.com/')
- self.assertIsInstance(t, Transport)
- self.assertIsInstance(t, HttpTransport_urllib)
-
-
class TestRangeHeader(tests.TestCase):
"""Test range_header method"""
@@ -247,153 +224,6 @@
tail=50)
-class TestWallServer(object):
- """Tests exceptions during the connection phase"""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(WallRequestHandler)
-
- def test_http_has(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- # Unfortunately httplib (see HTTPResponse._read_status
- # for details) make no distinction between a closed
- # socket and badly formatted status line, so we can't
- # just test for ConnectionError, we have to test
- # InvalidHttpResponse too.
- self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
- t.has, 'foo/bar')
-
- def test_http_get(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
- t.get, 'foo/bar')
-
-
-class TestWallServer_urllib(TestWallServer, TestCaseWithWebserver):
- """Tests "wall" server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestWallServer_pycurl(TestWithTransport_pycurl,
- TestWallServer,
- TestCaseWithWebserver):
- """Tests "wall" server for pycurl implementation"""
-
-
-class TestBadStatusServer(object):
- """Tests bad status from server."""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(BadStatusRequestHandler)
-
- def test_http_has(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
-
- def test_http_get(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
-
-
-class TestBadStatusServer_urllib(TestBadStatusServer, TestCaseWithWebserver):
- """Tests bad status server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestBadStatusServer_pycurl(TestWithTransport_pycurl,
- TestBadStatusServer,
- TestCaseWithWebserver):
- """Tests bad status server for pycurl implementation"""
-
-
-class TestInvalidStatusServer(TestBadStatusServer):
- """Tests invalid status from server.
-
- Both implementations raises the same error as for a bad status.
- """
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(InvalidStatusRequestHandler)
-
-
-class TestInvalidStatusServer_urllib(TestInvalidStatusServer,
- TestCaseWithWebserver):
- """Tests invalid status server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestInvalidStatusServer_pycurl(TestWithTransport_pycurl,
- TestInvalidStatusServer,
- TestCaseWithWebserver):
- """Tests invalid status server for pycurl implementation"""
-
-
-class TestBadProtocolServer(object):
- """Tests bad protocol from server."""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(BadProtocolRequestHandler)
-
- def test_http_has(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
-
- def test_http_get(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
-
-
-class TestBadProtocolServer_urllib(TestBadProtocolServer,
- TestCaseWithWebserver):
- """Tests bad protocol server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-# curl don't check the protocol version
-#class TestBadProtocolServer_pycurl(TestWithTransport_pycurl,
-# TestBadProtocolServer,
-# TestCaseWithWebserver):
-# """Tests bad protocol server for pycurl implementation"""
-
-
-class TestForbiddenServer(object):
- """Tests forbidden server"""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(ForbiddenRequestHandler)
-
- def test_http_has(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.TransportError, t.has, 'foo/bar')
-
- def test_http_get(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- self.assertRaises(errors.TransportError, t.get, 'foo/bar')
-
-
-class TestForbiddenServer_urllib(TestForbiddenServer, TestCaseWithWebserver):
- """Tests forbidden server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestForbiddenServer_pycurl(TestWithTransport_pycurl,
- TestForbiddenServer,
- TestCaseWithWebserver):
- """Tests forbidden server for pycurl implementation"""
-
-
class TestRecordingServer(tests.TestCase):
def test_create(self):
@@ -425,204 +255,6 @@
self.assertEqual('abc', server.received_bytes)
-class TestRangeRequestServer(object):
- """Tests readv requests against server.
-
- This MUST be used by daughter classes that also inherit from
- TestCaseWithWebserver.
-
- We can't inherit directly from TestCaseWithWebserver or the
- test framework will try to create an instance which cannot
- run, its implementation being incomplete.
- """
-
- def setUp(self):
- TestCaseWithWebserver.setUp(self)
- self.build_tree_contents([('a', '0123456789')],)
-
- def test_readv(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
- self.assertEqual(l[0], (0, '0'))
- self.assertEqual(l[1], (1, '1'))
- self.assertEqual(l[2], (3, '34'))
- self.assertEqual(l[3], (9, '9'))
-
- def test_readv_out_of_order(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
- self.assertEqual(l[0], (1, '1'))
- self.assertEqual(l[1], (9, '9'))
- self.assertEqual(l[2], (0, '0'))
- self.assertEqual(l[3], (3, '34'))
-
- def test_readv_invalid_ranges(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
-
- # This is intentionally reading off the end of the file
- # since we are sure that it cannot get there
- self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
- t.readv, 'a', [(1,1), (8,10)])
-
- # This is trying to seek past the end of the file, it should
- # also raise a special error
- self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
- t.readv, 'a', [(12,2)])
-
- def test_readv_multiple_get_requests(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- # force transport to issue multiple requests
- t._max_readv_combine = 1
- t._max_get_ranges = 1
- l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
- self.assertEqual(l[0], (0, '0'))
- self.assertEqual(l[1], (1, '1'))
- self.assertEqual(l[2], (3, '34'))
- self.assertEqual(l[3], (9, '9'))
- # The server should have issued 4 requests
- self.assertEqual(4, server.GET_request_nb)
-
- def test_readv_get_max_size(self):
- server = self.get_readonly_server()
- t = self._transport(server.get_url())
- # force transport to issue multiple requests by limiting the number of
- # bytes by request. Note that this apply to coalesced offsets only, a
- # single range ill keep its size even if bigger than the limit.
- t._get_max_size = 2
- l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
- self.assertEqual(l[0], (0, '0'))
- self.assertEqual(l[1], (1, '1'))
- self.assertEqual(l[2], (2, '2345'))
- self.assertEqual(l[3], (6, '6789'))
- # The server should have issued 3 requests
- self.assertEqual(3, server.GET_request_nb)
-
-
-class TestSingleRangeRequestServer(TestRangeRequestServer):
- """Test readv against a server which accept only single range requests"""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(SingleRangeRequestHandler)
-
-
-class TestSingleRangeRequestServer_urllib(TestSingleRangeRequestServer,
- TestCaseWithWebserver):
- """Tests single range requests accepting server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestSingleRangeRequestServer_pycurl(TestWithTransport_pycurl,
- TestSingleRangeRequestServer,
- TestCaseWithWebserver):
- """Tests single range requests accepting server for pycurl implementation"""
-
-
-class TestSingleOnlyRangeRequestServer(TestRangeRequestServer):
- """Test readv against a server which only accept single range requests"""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(SingleOnlyRangeRequestHandler)
-
-
-class TestSingleOnlyRangeRequestServer_urllib(TestSingleOnlyRangeRequestServer,
- TestCaseWithWebserver):
- """Tests single range requests accepting server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestSingleOnlyRangeRequestServer_pycurl(TestWithTransport_pycurl,
- TestSingleOnlyRangeRequestServer,
- TestCaseWithWebserver):
- """Tests single range requests accepting server for pycurl implementation"""
-
-
-class TestNoRangeRequestServer(TestRangeRequestServer):
- """Test readv against a server which do not accept range requests"""
-
- def create_transport_readonly_server(self):
- return http_server.HttpServer(NoRangeRequestHandler)
-
-
-class TestNoRangeRequestServer_urllib(TestNoRangeRequestServer,
- TestCaseWithWebserver):
- """Tests range requests refusing server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestNoRangeRequestServer_pycurl(TestWithTransport_pycurl,
- TestNoRangeRequestServer,
- TestCaseWithWebserver):
- """Tests range requests refusing server for pycurl implementation"""
-
-
-class TestLimitedRangeRequestServer(object):
- """Tests readv requests against server that errors out on too much ranges.
-
- This MUST be used by daughter classes that also inherit from
- TestCaseWithWebserver.
-
- We can't inherit directly from TestCaseWithWebserver or the
- test framework will try to create an instance which cannot
- run, its implementation being incomplete.
- """
-
- range_limit = 3
-
- def create_transport_readonly_server(self):
- # Requests with more range specifiers will error out
- return LimitedRangeHTTPServer(range_limit=self.range_limit)
-
- def get_transport(self):
- return self._transport(self.get_readonly_server().get_url())
-
- def setUp(self):
- TestCaseWithWebserver.setUp(self)
- # We need to manipulate ranges that correspond to real chunks in the
- # response, so we build a content appropriately.
- filler = ''.join(['abcdefghij' for x in range(102)])
- content = ''.join(['%04d' % v + filler for v in range(16)])
- self.build_tree_contents([('a', content)],)
-
- def test_few_ranges(self):
- t = self.get_transport()
- l = list(t.readv('a', ((0, 4), (1024, 4), )))
- self.assertEqual(l[0], (0, '0000'))
- self.assertEqual(l[1], (1024, '0001'))
- self.assertEqual(1, self.get_readonly_server().GET_request_nb)
-
- def test_more_ranges(self):
- t = self.get_transport()
- l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
- self.assertEqual(l[0], (0, '0000'))
- self.assertEqual(l[1], (1024, '0001'))
- self.assertEqual(l[2], (4096, '0004'))
- self.assertEqual(l[3], (8192, '0008'))
- # The server will refuse to serve the first request (too much ranges),
- # a second request will succeeds.
- self.assertEqual(2, self.get_readonly_server().GET_request_nb)
-
-
-class TestLimitedRangeRequestServer_urllib(TestLimitedRangeRequestServer,
- TestCaseWithWebserver):
- """Tests limited range requests server for urllib implementation"""
-
- _transport = HttpTransport_urllib
-
-
-class TestLimitedRangeRequestServer_pycurl(TestWithTransport_pycurl,
- TestLimitedRangeRequestServer,
- TestCaseWithWebserver):
- """Tests limited range requests server for pycurl implementation"""
-
-
-
class TestHttpProxyWhiteBox(tests.TestCase):
"""Whitebox test proxy http authorization.
=== modified file 'bzrlib/tests/test_http_implementations.py'
--- a/bzrlib/tests/test_http_implementations.py 2007-12-19 09:29:21 +0000
+++ b/bzrlib/tests/test_http_implementations.py 2007-12-19 11:29:12 +0000
@@ -25,6 +25,7 @@
protocol implementation to guarantee the robustness of our transports.
"""
+import SimpleHTTPServer
import socket
import bzrlib
@@ -190,3 +191,372 @@
server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
+class TestHttpTransportRegistration(tests.TestCase):
+ """Test registrations of various http implementations"""
+
+ def test_http_registered(self):
+ t = transport.get_transport('%s://foo.com/' % self._qualified_prefix)
+ self.assertIsInstance(t, transport.Transport)
+ self.assertIsInstance(t, self._transport)
+
+
+class TestSpecificRequestHandler(http_utils.TestCaseWithWebserver):
+ """Tests a specific request handler.
+
+
+ Daughter class are expected to override _req_handler_class
+ """
+
+ # Provide a useful default
+ _req_handler_class = http_server.TestingHTTPRequestHandler
+
+ def create_transport_readonly_server(self):
+ return http_server.HttpServer(self._req_handler_class)
+
+
+class WallRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Whatever request comes in, close the connection"""
+
+ def handle_one_request(self):
+ """Handle a single HTTP request, by abruptly closing the connection"""
+ self.close_connection = 1
+
+
+class TestWallServer(TestSpecificRequestHandler):
+ """Tests exceptions during the connection phase"""
+
+ _req_handler_class = WallRequestHandler
+
+ def test_http_has(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ # Unfortunately httplib (see HTTPResponse._read_status
+ # for details) make no distinction between a closed
+ # socket and badly formatted status line, so we can't
+ # just test for ConnectionError, we have to test
+ # InvalidHttpResponse too.
+ self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
+ t.has, 'foo/bar')
+
+ def test_http_get(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
+ t.get, 'foo/bar')
+
+
+class BadStatusRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Whatever request comes in, returns a bad status"""
+
+ def parse_request(self):
+ """Fakes handling a single HTTP request, returns a bad status"""
+ ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
+ try:
+ self.send_response(0, "Bad status")
+ self.end_headers()
+ except socket.error, e:
+ # We don't want to pollute the test results with
+ # spurious server errors while test succeed. In our
+ # case, it may occur that the test has already read
+ # the 'Bad Status' and closed the socket while we are
+ # still trying to send some headers... So the test is
+ # ok, but if we raise the exception, the output is
+ # dirty. So we don't raise, but we close the
+ # connection, just to be safe :)
+ spurious = [errno.EPIPE,
+ errno.ECONNRESET,
+ errno.ECONNABORTED,
+ ]
+ if (len(e.args) > 0) and (e.args[0] in spurious):
+ self.close_connection = 1
+ pass
+ else:
+ raise
+ return False
+
+
+class TestBadStatusServer(TestSpecificRequestHandler):
+ """Tests bad status from server."""
+
+ _req_handler_class = BadStatusRequestHandler
+
+ def test_http_has(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
+
+ def test_http_get(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
+
+
+class InvalidStatusRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Whatever request comes in, returns am invalid status"""
+
+ def parse_request(self):
+ """Fakes handling a single HTTP request, returns a bad status"""
+ ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
+ self.wfile.write("Invalid status line\r\n")
+ return False
+
+
+class TestInvalidStatusServer(TestBadStatusServer):
+ """Tests invalid status from server.
+
+ Both implementations raises the same error as for a bad status.
+ """
+
+ _req_handler_class = InvalidStatusRequestHandler
+
+
+class BadProtocolRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Whatever request comes in, returns a bad protocol version"""
+
+ def parse_request(self):
+ """Fakes handling a single HTTP request, returns a bad status"""
+ ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
+ # Returns an invalid protocol version, but curl just
+ # ignores it and those cannot be tested.
+ self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
+ 404,
+ 'Look at my protocol version'))
+ return False
+
+
+class TestBadProtocolServer(TestSpecificRequestHandler):
+ """Tests bad protocol from server."""
+
+ _req_handler_class = BadProtocolRequestHandler
+
+ def setUp(self):
+ if pycurl_present and self._transport == PyCurlTransport:
+ raise tests.TestNotApplicable(
+ "pycurl doesn't check the protocol version")
+ super(TestBadProtocolServer, self).setUp()
+
+ def test_http_has(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
+
+ def test_http_get(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
+
+
+class ForbiddenRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Whatever request comes in, returns a 403 code"""
+
+ def parse_request(self):
+ """Handle a single HTTP request, by replying we cannot handle it"""
+ ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
+ self.send_error(403)
+ return False
+
+
+class TestForbiddenServer(TestSpecificRequestHandler):
+ """Tests forbidden server"""
+
+ _req_handler_class = ForbiddenRequestHandler
+
+ def test_http_has(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.TransportError, t.has, 'foo/bar')
+
+ def test_http_get(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ self.assertRaises(errors.TransportError, t.get, 'foo/bar')
+
+
+class TestRangeRequestServer(TestSpecificRequestHandler):
+ """Tests readv requests against server.
+
+ We test against default "normal" server.
+ """
+
+ def setUp(self):
+ super(TestRangeRequestServer, self).setUp()
+ self.build_tree_contents([('a', '0123456789')],)
+
+ def test_readv(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
+ self.assertEqual(l[0], (0, '0'))
+ self.assertEqual(l[1], (1, '1'))
+ self.assertEqual(l[2], (3, '34'))
+ self.assertEqual(l[3], (9, '9'))
+
+ def test_readv_out_of_order(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
+ self.assertEqual(l[0], (1, '1'))
+ self.assertEqual(l[1], (9, '9'))
+ self.assertEqual(l[2], (0, '0'))
+ self.assertEqual(l[3], (3, '34'))
+
+ def test_readv_invalid_ranges(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+
+ # This is intentionally reading off the end of the file
+ # since we are sure that it cannot get there
+ self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
+ t.readv, 'a', [(1,1), (8,10)])
+
+ # This is trying to seek past the end of the file, it should
+ # also raise a special error
+ self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
+ t.readv, 'a', [(12,2)])
+
+ def test_readv_multiple_get_requests(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ # force transport to issue multiple requests
+ t._max_readv_combine = 1
+ t._max_get_ranges = 1
+ l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
+ self.assertEqual(l[0], (0, '0'))
+ self.assertEqual(l[1], (1, '1'))
+ self.assertEqual(l[2], (3, '34'))
+ self.assertEqual(l[3], (9, '9'))
+ # The server should have issued 4 requests
+ self.assertEqual(4, server.GET_request_nb)
+
+ def test_readv_get_max_size(self):
+ server = self.get_readonly_server()
+ t = self._transport(server.get_url())
+ # force transport to issue multiple requests by limiting the number of
+ # bytes by request. Note that this apply to coalesced offsets only, a
+ # single range ill keep its size even if bigger than the limit.
+ t._get_max_size = 2
+ l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
+ self.assertEqual(l[0], (0, '0'))
+ self.assertEqual(l[1], (1, '1'))
+ self.assertEqual(l[2], (2, '2345'))
+ self.assertEqual(l[3], (6, '6789'))
+ # The server should have issued 3 requests
+ self.assertEqual(3, server.GET_request_nb)
+
+
+class SingleRangeRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Always reply to range request as if they were single.
+
+ Don't be explicit about it, just to annoy the clients.
+ """
+
+ def get_multiple_ranges(self, file, file_size, ranges):
+ """Answer as if it was a single range request and ignores the rest"""
+ (start, end) = ranges[0]
+ return self.get_single_range(file, file_size, start, end)
+
+
+class TestSingleRangeRequestServer(TestRangeRequestServer):
+ """Test readv against a server which accept only single range requests"""
+
+ _req_handler_class = SingleRangeRequestHandler
+
+
+class SingleOnlyRangeRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Only reply to simple range requests, errors out on multiple"""
+
+ def get_multiple_ranges(self, file, file_size, ranges):
+ """Refuses the multiple ranges request"""
+ if len(ranges) > 1:
+ file.close()
+ self.send_error(416, "Requested range not satisfiable")
+ return
+ (start, end) = ranges[0]
+ return self.get_single_range(file, file_size, start, end)
+
+
+class TestSingleOnlyRangeRequestServer(TestRangeRequestServer):
+ """Test readv against a server which only accept single range requests"""
+
+ _req_handler_class = SingleOnlyRangeRequestHandler
+
+
+class NoRangeRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Ignore range requests without notice"""
+
+ def do_GET(self):
+ # Update the statistics
+ self.server.test_case_server.GET_request_nb += 1
+ # Just bypass the range handling done by TestingHTTPRequestHandler
+ return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+
+
+class TestNoRangeRequestServer(TestRangeRequestServer):
+ """Test readv against a server which do not accept range requests"""
+
+ _req_handler_class = NoRangeRequestHandler
+
+
+class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
+ """Errors out when range specifiers exceed the limit"""
+
+ def get_multiple_ranges(self, file, file_size, ranges):
+ """Refuses the multiple ranges request"""
+ tcs = self.server.test_case_server
+ if tcs.range_limit is not None and len(ranges) > tcs.range_limit:
+ file.close()
+ # Emulate apache behavior
+ self.send_error(400, "Bad Request")
+ return
+ return http_server.TestingHTTPRequestHandler.get_multiple_ranges(
+ self, file, file_size, ranges)
+
+
+class LimitedRangeHTTPServer(http_server.HttpServer):
+ """An HttpServer erroring out on requests with too much range specifiers"""
+
+ def __init__(self, request_handler=LimitedRangeRequestHandler,
+ range_limit=None):
+ http_server.HttpServer.__init__(self, request_handler)
+ self.range_limit = range_limit
+
+
+class TestLimitedRangeRequestServer(http_utils.TestCaseWithWebserver):
+ """Tests readv requests against a server erroring out on too much ranges."""
+
+ range_limit = 3
+
+ def create_transport_readonly_server(self):
+ # Requests with more range specifiers will error out
+ return LimitedRangeHTTPServer(range_limit=self.range_limit)
+
+ def get_transport(self):
+ return self._transport(self.get_readonly_server().get_url())
+
+ def setUp(self):
+ http_utils.TestCaseWithWebserver.setUp(self)
+ # We need to manipulate ranges that correspond to real chunks in the
+ # response, so we build a content appropriately.
+ filler = ''.join(['abcdefghij' for x in range(102)])
+ content = ''.join(['%04d' % v + filler for v in range(16)])
+ self.build_tree_contents([('a', content)],)
+
+ def test_few_ranges(self):
+ t = self.get_transport()
+ l = list(t.readv('a', ((0, 4), (1024, 4), )))
+ self.assertEqual(l[0], (0, '0000'))
+ self.assertEqual(l[1], (1024, '0001'))
+ self.assertEqual(1, self.get_readonly_server().GET_request_nb)
+
+ def test_more_ranges(self):
+ t = self.get_transport()
+ l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
+ self.assertEqual(l[0], (0, '0000'))
+ self.assertEqual(l[1], (1024, '0001'))
+ self.assertEqual(l[2], (4096, '0004'))
+ self.assertEqual(l[3], (8192, '0008'))
+ # The server will refuse to serve the first request (too much ranges),
+ # a second request will succeeds.
+ self.assertEqual(2, self.get_readonly_server().GET_request_nb)
+
+
More information about the bazaar-commits
mailing list