1
# Copyright (C) 2005, 2006 Canonical
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# FIXME: This test should be repeated for each available http client
18
# implementation; at the moment we have urllib and pycurl.
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
25
from bzrlib.errors import (DependencyNotPresent,
28
from bzrlib.tests import TestCase, TestSkipped
29
from bzrlib.transport import Transport
30
from bzrlib.transport.http import (
35
from bzrlib.transport.http._urllib import HttpTransport_urllib
36
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
39
class FakeManager (object):
44
def add_password(self, realm, host, username, password):
45
self.credentials.append([realm, host, username, password])
48
class TestHttpUrls(TestCase):
50
def test_url_parsing(self):
52
url = extract_auth('http://example.com', f)
53
self.assertEquals('http://example.com', url)
54
self.assertEquals(0, len(f.credentials))
55
url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
56
self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
57
self.assertEquals(1, len(f.credentials))
58
self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
61
def test_abs_url(self):
62
"""Construction of absolute http URLs"""
63
t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
64
eq = self.assertEqualDiff
66
'http://bazaar-vcs.org/bzr/bzr.dev')
67
eq(t.abspath('foo/bar'),
68
'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
70
'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
71
eq(t.abspath('.bzr/1//2/./3'),
72
'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
74
def test_invalid_http_urls(self):
75
"""Trap invalid construction of urls"""
76
t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
77
self.assertRaises(ValueError,
81
def test_http_root_urls(self):
82
"""Construction of URLs from server root"""
83
t = HttpTransport_urllib('http://bzr.ozlabs.org/')
84
eq = self.assertEqualDiff
85
eq(t.abspath('.bzr/tree-version'),
86
'http://bzr.ozlabs.org/.bzr/tree-version')
88
def test_http_impl_urls(self):
89
"""There are servers which ask for particular clients to connect"""
91
from bzrlib.transport.http._pycurl import HttpServer_PyCurl
92
server = HttpServer_PyCurl()
95
url = server.get_url()
96
self.assertTrue(url.startswith('http+pycurl://'))
99
except DependencyNotPresent:
100
raise TestSkipped('pycurl not present')
103
class TestHttpMixins(object):
105
def _prep_tree(self):
106
self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
107
transport=self.get_transport())
109
def test_http_has(self):
110
server = self.get_readonly_server()
111
t = self._transport(server.get_url())
112
self.assertEqual(t.has('foo/bar'), True)
113
self.assertEqual(len(server.logs), 1)
114
self.assertContainsRe(server.logs[0],
115
r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
117
def test_http_has_not_found(self):
118
server = self.get_readonly_server()
119
t = self._transport(server.get_url())
120
self.assertEqual(t.has('not-found'), False)
121
self.assertContainsRe(server.logs[1],
122
r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
124
def test_http_get(self):
125
server = self.get_readonly_server()
126
t = self._transport(server.get_url())
127
fp = t.get('foo/bar')
128
self.assertEqualDiff(
130
'contents of foo/bar\n')
131
self.assertEqual(len(server.logs), 1)
132
self.assertTrue(server.logs[0].find(
133
'"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s' % bzrlib.__version__) > -1)
136
class TestHttpConnections_urllib(TestCaseWithWebserver, TestHttpMixins):
138
_transport = HttpTransport_urllib
141
TestCaseWithWebserver.setUp(self)
144
def test_has_on_bogus_host(self):
145
# Get a free address and don't 'accept' on it, so that we
146
# can be sure there is no http handler there, but set a
147
# reasonable timeout to not slow down tests too much.
148
default_timeout = socket.getdefaulttimeout()
150
socket.setdefaulttimeout(2)
152
s.bind(('localhost', 0))
153
t = self._transport('http://%s:%s/' % s.getsockname())
154
self.assertRaises(ConnectionError, t.has, 'foo/bar')
156
socket.setdefaulttimeout(default_timeout)
159
class TestHttpConnections_pycurl(TestCaseWithWebserver, TestHttpMixins):
161
def _get_pycurl_maybe(self):
163
from bzrlib.transport.http._pycurl import PyCurlTransport
164
return PyCurlTransport
165
except DependencyNotPresent:
166
raise TestSkipped('pycurl not present')
168
_transport = property(_get_pycurl_maybe)
171
TestCaseWithWebserver.setUp(self)
175
class TestHttpTransportRegistration(TestCase):
176
"""Test registrations of various http implementations"""
178
def test_http_registered(self):
179
import bzrlib.transport.http._urllib
180
from bzrlib.transport import get_transport
181
# urlllib should always be present
182
t = get_transport('http+urllib://bzr.google.com/')
183
self.assertIsInstance(t, Transport)
184
self.assertIsInstance(t, bzrlib.transport.http._urllib.HttpTransport_urllib)
187
class TestOffsets(TestCase):
188
"""Test offsets_to_ranges method"""
190
def test_offsets_to_ranges_simple(self):
191
to_range = HttpTransportBase.offsets_to_ranges
192
ranges = to_range([(10, 1)])
193
self.assertEqual([[10, 10]], ranges)
195
ranges = to_range([(0, 1), (1, 1)])
196
self.assertEqual([[0, 1]], ranges)
198
ranges = to_range([(1, 1), (0, 1)])
199
self.assertEqual([[0, 1]], ranges)
201
def test_offset_to_ranges_overlapped(self):
202
to_range = HttpTransportBase.offsets_to_ranges
204
ranges = to_range([(10, 1), (20, 2), (22, 5)])
205
self.assertEqual([[10, 10], [20, 26]], ranges)
207
ranges = to_range([(10, 1), (11, 2), (22, 5)])
208
self.assertEqual([[10, 12], [22, 26]], ranges)
211
class TestRangeHeader(TestCase):
212
"""Test range_header method"""
214
def check_header(self, value, ranges=[], tail=0):
215
range_header = HttpTransportBase.range_header
216
self.assertEqual(value, range_header(ranges, tail))
218
def test_range_header_single(self):
219
self.check_header('0-9', ranges=[[0,9]])
220
self.check_header('100-109', ranges=[[100,109]])
222
def test_range_header_tail(self):
223
self.check_header('-10', tail=10)
224
self.check_header('-50', tail=50)
226
def test_range_header_multi(self):
227
self.check_header('0-9,100-200,300-5000',
228
ranges=[(0,9), (100, 200), (300,5000)])
230
def test_range_header_mixed(self):
231
self.check_header('0-9,300-5000,-50',
232
ranges=[(0,9), (300,5000)],
235
# TODO: We need to generalize the following tests to all
236
# transports which connect to a server via a socket. Is there a
237
# way to add an accessor or an attribute to this transports so
238
# that we can filter them from the list of all existing
240
class TestBogusServer(TestCaseWithWebserver):
241
"""Abstract class to define test for all bogus servers"""
243
#from bzrlib.transport.http._pycurl import PyCurlTransport
244
#_transport = PyCurlTransport
245
_transport = HttpTransport_urllib
248
server = self.get_server()
249
t = self._transport(server.get_url())
250
self.assertRaises(ConnectionError, t.has, 'foo/bar')
253
server = self.get_server()
254
t = self._transport(server.get_url())
255
self.assertRaises(ConnectionError, t.get, 'foo/bar')
258
class TestWallServer(TestBogusServer):
259
"""Tests that we get the right exceptions during the connection phase"""
260
def create_transport_server(self):
261
return bzrlib.transport.http.HttpServer(WallRequestHandler)