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?
23
from bzrlib.errors import DependencyNotPresent
24
from bzrlib.tests import TestCase, TestSkipped
25
from bzrlib.transport import Transport
26
from bzrlib.transport.http import extract_auth, HttpTransportBase
27
from bzrlib.transport.http._urllib import HttpTransport_urllib
28
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
31
class FakeManager (object):
36
def add_password(self, realm, host, username, password):
37
self.credentials.append([realm, host, username, password])
3
from bzrlib.selftest import TestCase
4
from bzrlib.transport.http import HttpTransport
40
6
class TestHttpUrls(TestCase):
42
def test_url_parsing(self):
44
url = extract_auth('http://example.com', f)
45
self.assertEquals('http://example.com', url)
46
self.assertEquals(0, len(f.credentials))
47
url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
48
self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
49
self.assertEquals(1, len(f.credentials))
50
self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'], f.credentials[0])
52
7
def test_abs_url(self):
53
8
"""Construction of absolute http URLs"""
54
t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
9
t = HttpTransport('http://bazaar-ng.org/bzr/bzr.dev/')
55
10
eq = self.assertEqualDiff
57
'http://bazaar-vcs.org/bzr/bzr.dev')
12
'http://bazaar-ng.org/bzr/bzr.dev')
58
13
eq(t.abspath('foo/bar'),
59
'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
14
'http://bazaar-ng.org/bzr/bzr.dev/foo/bar')
60
15
eq(t.abspath('.bzr'),
61
'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
16
'http://bazaar-ng.org/bzr/bzr.dev/.bzr')
62
17
eq(t.abspath('.bzr/1//2/./3'),
63
'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
18
'http://bazaar-ng.org/bzr/bzr.dev/.bzr/1/2/3')
65
20
def test_invalid_http_urls(self):
66
21
"""Trap invalid construction of urls"""
67
t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
22
t = HttpTransport('http://bazaar-ng.org/bzr/bzr.dev/')
68
23
self.assertRaises(ValueError,
75
30
def test_http_root_urls(self):
76
31
"""Construction of URLs from server root"""
77
t = HttpTransport_urllib('http://bzr.ozlabs.org/')
32
t = HttpTransport('http://bzr.ozlabs.org/')
78
33
eq = self.assertEqualDiff
79
34
eq(t.abspath('.bzr/tree-version'),
80
35
'http://bzr.ozlabs.org/.bzr/tree-version')
82
def test_http_impl_urls(self):
83
"""There are servers which ask for particular clients to connect"""
85
from bzrlib.transport.http._pycurl import HttpServer_PyCurl
86
server = HttpServer_PyCurl()
89
url = server.get_url()
90
self.assertTrue(url.startswith('http+pycurl://'))
93
except DependencyNotPresent:
94
raise TestSkipped('pycurl not present')
97
class TestHttpMixins(object):
100
self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
101
transport=self.get_transport())
103
def test_http_has(self):
104
server = self.get_readonly_server()
105
t = self._transport(server.get_url())
106
self.assertEqual(t.has('foo/bar'), True)
107
self.assertEqual(len(server.logs), 1)
108
self.assertContainsRe(server.logs[0],
109
r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
111
def test_http_has_not_found(self):
112
server = self.get_readonly_server()
113
t = self._transport(server.get_url())
114
self.assertEqual(t.has('not-found'), False)
115
self.assertContainsRe(server.logs[1],
116
r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
118
def test_http_get(self):
119
server = self.get_readonly_server()
120
t = self._transport(server.get_url())
121
fp = t.get('foo/bar')
122
self.assertEqualDiff(
124
'contents of foo/bar\n')
125
self.assertEqual(len(server.logs), 1)
126
self.assertTrue(server.logs[0].find(
127
'"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s' % bzrlib.__version__) > -1)
130
class TestHttpConnections_urllib(TestCaseWithWebserver, TestHttpMixins):
132
_transport = HttpTransport_urllib
135
TestCaseWithWebserver.setUp(self)
140
class TestHttpConnections_pycurl(TestCaseWithWebserver, TestHttpMixins):
142
def _get_pycurl_maybe(self):
144
from bzrlib.transport.http._pycurl import PyCurlTransport
145
return PyCurlTransport
146
except DependencyNotPresent:
147
raise TestSkipped('pycurl not present')
149
_transport = property(_get_pycurl_maybe)
152
TestCaseWithWebserver.setUp(self)
157
class TestHttpTransportRegistration(TestCase):
158
"""Test registrations of various http implementations"""
160
def test_http_registered(self):
161
import bzrlib.transport.http._urllib
162
from bzrlib.transport import get_transport
163
# urlllib should always be present
164
t = get_transport('http+urllib://bzr.google.com/')
165
self.assertIsInstance(t, Transport)
166
self.assertIsInstance(t, bzrlib.transport.http._urllib.HttpTransport_urllib)
169
class TestOffsets(TestCase):
170
"""Test offsets_to_ranges method"""
172
def test_offsets_to_ranges_simple(self):
173
to_range = HttpTransportBase.offsets_to_ranges
174
ranges, tail = to_range([(10, 1)])
175
self.assertEqual([[10, 10]], ranges)
176
self.assertEqual(0, tail)
178
ranges, tail = to_range([(0, 1), (1, 1)])
179
self.assertEqual([[0, 1]], ranges)
180
self.assertEqual(0, tail)
182
ranges, tail = to_range([(1, 1), (0, 1)])
183
self.assertEqual([[0, 1]], ranges)
184
self.assertEqual(0, tail)
186
def test_offset_to_ranges_overlapped(self):
187
to_range = HttpTransportBase.offsets_to_ranges
189
ranges, tail = to_range([(10, 1), (20, 2), (22, 5)])
190
self.assertEquals(tuple(ranges[0]), (10, 10))
191
self.assertEquals(tuple(ranges[1]), (20, 26))
192
self.assertEquals(tail, 0)
194
ranges, tail = to_range([(10, 1), (11, 2), (22, 5), (-4, 4)])
195
self.assertEquals(tuple(ranges[0]), (10, 12))
196
self.assertEquals(tuple(ranges[1]), (22, 26))
197
self.assertEquals(tail, 4)
199
def test_offset_to_ranges_tail(self):
200
to_range = HttpTransportBase.offsets_to_ranges
202
ranges, tail = to_range([(-4, 4), (-8, 8)])
203
self.assertEquals(tuple(ranges), ())
204
self.assertEquals(tail, 8)
206
def test_offset_to_ranges_fudge(self):
207
to_range = HttpTransportBase.offsets_to_ranges
209
ranges, tail = to_range([(10, 1), (20, 2)], fudge_factor=9)
210
self.assertEquals(tuple(ranges[0]), (10, 21))
211
self.assertEquals(len(ranges), 1)
212
self.assertEquals(tail, 0)
214
ranges, tail = to_range([(10, 1), (20, 2)], fudge_factor=8)
215
self.assertEquals(tuple(ranges[0]), (10, 10))
216
self.assertEquals(tuple(ranges[1]), (20, 21))
217
self.assertEquals(tail, 0)
220
class TestRangeHeader(TestCase):
221
"""Test range_header method"""
223
def check_header(self, value, ranges=[], tail=0):
224
range_header = HttpTransportBase.range_header
225
self.assertEqual(value, range_header(ranges, tail))
227
def test_range_header_single(self):
228
self.check_header('bytes=0-9', ranges=[[0,9]])
229
self.check_header('bytes=100-109', ranges=[[100,109]])
231
def test_range_header_tail(self):
232
self.check_header('bytes=-10', tail=10)
233
self.check_header('bytes=-50', tail=50)
235
def test_range_header_multi(self):
236
self.check_header('bytes=0-9,100-200,300-5000',
237
ranges=[(0,9), (100, 200), (300,5000)])
239
def test_range_header_mixed(self):
240
self.check_header('bytes=0-9,300-5000,-50',
241
ranges=[(0,9), (300,5000)],