/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: v.ladeuil+lp at free
  • Date: 2006-10-12 14:29:32 UTC
  • mto: (2145.1.1 keepalive)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: v.ladeuil+lp@free.fr-20061012142932-7221fe16d2b48fa3
Shuffle http related test code. Hopefully it ends up at the right place :)

* bzrlib/tests/HttpServer.py: 
New file. bzrlib.tests.ChrootedTestCase use HttpServer. So the
class can't be defined in bzrlib.tests.HTTPUtils because it
creates a circular dependency (bzrlib.tests.HTTPUtils needs to
import bzrlib.tests).

* bzrlib/transport/http/_urllib.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/_pycurl.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/__init__.py: 
Transfer all test related code to either bzrlib.tests.HttpServer
and bzrlib.tests.HTTPUtils.
Fix all use of TransportNotPossible and InvalidURL by prefixing it
by 'errors.' (this seems to be the preferred way in the rest of
bzr).
Get rid of unused imports.

* bzrlib/tests/test_transport.py:
(ReadonlyDecoratorTransportTest.test_local_parameters,
FakeNFSDecoratorTests.test_http_parameters): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_sftp_transport.py:
(set_test_transport_to_sftp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_selftest.py:
(TestTestCaseWithTransport.test_get_readonly_url_http): Use
HttpServer from bzrlib.tests.HttpServer instead of
bzrlib.transport.http.

* bzrlib/tests/test_repository.py: 
Does *not* use HttpServer.

* bzrlib/tests/test_http.py: 
Build on top of bzrlib.tests.HttpServer and bzrlib.tests.HTTPUtils
instead of bzrlib.transport.http.

* bzrlib/tests/test_bzrdir.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_http.py:
(HTTPBranchTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_branch.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/__init__.py:
(ChrootedTestCase.setUp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
# FIXME: This test should be repeated for each available http client
 
18
# implementation; at the moment we have urllib and pycurl.
 
19
 
 
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
 
21
 
 
22
import socket
 
23
 
 
24
import bzrlib
 
25
from bzrlib.errors import (
 
26
    DependencyNotPresent,
 
27
    ConnectionError,
 
28
    InvalidHttpResponse,
 
29
    )
 
30
from bzrlib.tests import (
 
31
    TestCase,
 
32
    TestSkipped,
 
33
    )
 
34
from bzrlib.tests.HttpServer import (
 
35
    HttpServer,
 
36
    HttpServer_PyCurl,
 
37
    HttpServer_urllib,
 
38
    )
 
39
from bzrlib.tests.HTTPTestUtil import (
 
40
    BadProtocolRequestHandler,
 
41
    BadStatusRequestHandler,
 
42
    InvalidStatusRequestHandler,
 
43
    TestCaseWithWebserver,
 
44
    WallRequestHandler,
 
45
    )
 
46
from bzrlib.transport import (
 
47
    get_transport,
 
48
    Transport,
 
49
    )
 
50
from bzrlib.transport.http import (
 
51
    extract_auth,
 
52
    HttpTransportBase,
 
53
    )
 
54
from bzrlib.transport.http._urllib import HttpTransport_urllib
 
55
 
 
56
 
 
57
class FakeManager (object):
 
58
 
 
59
    def __init__(self):
 
60
        self.credentials = []
 
61
 
 
62
    def add_password(self, realm, host, username, password):
 
63
        self.credentials.append([realm, host, username, password])
 
64
 
 
65
 
 
66
class TestHttpUrls(TestCase):
 
67
 
 
68
    def test_url_parsing(self):
 
69
        f = FakeManager()
 
70
        url = extract_auth('http://example.com', f)
 
71
        self.assertEquals('http://example.com', url)
 
72
        self.assertEquals(0, len(f.credentials))
 
73
        url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
 
74
        self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
 
75
        self.assertEquals(1, len(f.credentials))
 
76
        self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
 
77
                          f.credentials[0])
 
78
 
 
79
    def test_abs_url(self):
 
80
        """Construction of absolute http URLs"""
 
81
        t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
 
82
        eq = self.assertEqualDiff
 
83
        eq(t.abspath('.'),
 
84
           'http://bazaar-vcs.org/bzr/bzr.dev')
 
85
        eq(t.abspath('foo/bar'),
 
86
           'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
 
87
        eq(t.abspath('.bzr'),
 
88
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
 
89
        eq(t.abspath('.bzr/1//2/./3'),
 
90
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
 
91
 
 
92
    def test_invalid_http_urls(self):
 
93
        """Trap invalid construction of urls"""
 
94
        t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
 
95
        self.assertRaises(ValueError,
 
96
            t.abspath,
 
97
            '.bzr/')
 
98
 
 
99
    def test_http_root_urls(self):
 
100
        """Construction of URLs from server root"""
 
101
        t = HttpTransport_urllib('http://bzr.ozlabs.org/')
 
102
        eq = self.assertEqualDiff
 
103
        eq(t.abspath('.bzr/tree-version'),
 
104
           'http://bzr.ozlabs.org/.bzr/tree-version')
 
105
 
 
106
    def test_http_impl_urls(self):
 
107
        """There are servers which ask for particular clients to connect"""
 
108
        server = HttpServer_PyCurl()
 
109
        try:
 
110
            server.setUp()
 
111
            url = server.get_url()
 
112
            self.assertTrue(url.startswith('http+pycurl://'))
 
113
        finally:
 
114
            server.tearDown()
 
115
 
 
116
 
 
117
class TestHttpConnections(object):
 
118
    """Test the http connections.
 
119
 
 
120
    This MUST be used by daughter classes that also inherit from
 
121
    TestCaseWithWebserver.
 
122
 
 
123
    We can't inherit directly from TestCaseWithWebserver or the
 
124
    test framework will try to create an instance which cannot
 
125
    run, its implementation being incomplete.
 
126
    """
 
127
 
 
128
    def setUp(self):
 
129
        TestCaseWithWebserver.setUp(self)
 
130
        self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
 
131
                        transport=self.get_transport())
 
132
 
 
133
    def test_http_has(self):
 
134
        server = self.get_readonly_server()
 
135
        t = self._transport(server.get_url())
 
136
        self.assertEqual(t.has('foo/bar'), True)
 
137
        self.assertEqual(len(server.logs), 1)
 
138
        self.assertContainsRe(server.logs[0],
 
139
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
 
140
 
 
141
    def test_http_has_not_found(self):
 
142
        server = self.get_readonly_server()
 
143
        t = self._transport(server.get_url())
 
144
        self.assertEqual(t.has('not-found'), False)
 
145
        self.assertContainsRe(server.logs[1],
 
146
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
 
147
 
 
148
    def test_http_get(self):
 
149
        server = self.get_readonly_server()
 
150
        t = self._transport(server.get_url())
 
151
        fp = t.get('foo/bar')
 
152
        self.assertEqualDiff(
 
153
            fp.read(),
 
154
            'contents of foo/bar\n')
 
155
        self.assertEqual(len(server.logs), 1)
 
156
        self.assertTrue(server.logs[0].find(
 
157
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
 
158
            % bzrlib.__version__) > -1)
 
159
 
 
160
    def test_has_on_bogus_host(self):
 
161
        # Get a free address and don't 'accept' on it, so that we
 
162
        # can be sure there is no http handler there, but set a
 
163
        # reasonable timeout to not slow down tests too much.
 
164
        default_timeout = socket.getdefaulttimeout()
 
165
        try:
 
166
            socket.setdefaulttimeout(2)
 
167
            s = socket.socket()
 
168
            s.bind(('localhost', 0))
 
169
            t = self._transport('http://%s:%s/' % s.getsockname())
 
170
            self.assertRaises(ConnectionError, t.has, 'foo/bar')
 
171
        finally:
 
172
            socket.setdefaulttimeout(default_timeout)
 
173
 
 
174
 
 
175
class TestWithTransport_pycurl(object):
 
176
    """Test case to inherit from if pycurl is present"""
 
177
    def _get_pycurl_maybe(self):
 
178
        try:
 
179
            from bzrlib.transport.http._pycurl import PyCurlTransport
 
180
            return PyCurlTransport
 
181
        except DependencyNotPresent:
 
182
            raise TestSkipped('pycurl not present')
 
183
 
 
184
    _transport = property(_get_pycurl_maybe)
 
185
 
 
186
 
 
187
class TestHttpConnections_urllib(TestHttpConnections, TestCaseWithWebserver):
 
188
    """Test http connections with urllib"""
 
189
 
 
190
    _transport = HttpTransport_urllib
 
191
 
 
192
 
 
193
 
 
194
class TestHttpConnections_pycurl(TestWithTransport_pycurl,
 
195
                                 TestHttpConnections,
 
196
                                 TestCaseWithWebserver):
 
197
    """Test http connections with pycurl"""
 
198
 
 
199
 
 
200
class TestHttpTransportRegistration(TestCase):
 
201
    """Test registrations of various http implementations"""
 
202
 
 
203
    def test_http_registered(self):
 
204
        # urlllib should always be present
 
205
        t = get_transport('http+urllib://bzr.google.com/')
 
206
        self.assertIsInstance(t, Transport)
 
207
        self.assertIsInstance(t, HttpTransport_urllib)
 
208
 
 
209
 
 
210
class TestOffsets(TestCase):
 
211
    """Test offsets_to_ranges method"""
 
212
 
 
213
    def test_offsets_to_ranges_simple(self):
 
214
        to_range = HttpTransportBase.offsets_to_ranges
 
215
        ranges = to_range([(10, 1)])
 
216
        self.assertEqual([[10, 10]], ranges)
 
217
 
 
218
        ranges = to_range([(0, 1), (1, 1)])
 
219
        self.assertEqual([[0, 1]], ranges)
 
220
 
 
221
        ranges = to_range([(1, 1), (0, 1)])
 
222
        self.assertEqual([[0, 1]], ranges)
 
223
 
 
224
    def test_offset_to_ranges_overlapped(self):
 
225
        to_range = HttpTransportBase.offsets_to_ranges
 
226
 
 
227
        ranges = to_range([(10, 1), (20, 2), (22, 5)])
 
228
        self.assertEqual([[10, 10], [20, 26]], ranges)
 
229
 
 
230
        ranges = to_range([(10, 1), (11, 2), (22, 5)])
 
231
        self.assertEqual([[10, 12], [22, 26]], ranges)
 
232
 
 
233
 
 
234
class TestRangeHeader(TestCase):
 
235
    """Test range_header method"""
 
236
 
 
237
    def check_header(self, value, ranges=[], tail=0):
 
238
        range_header = HttpTransportBase.range_header
 
239
        self.assertEqual(value, range_header(ranges, tail))
 
240
 
 
241
    def test_range_header_single(self):
 
242
        self.check_header('0-9', ranges=[[0,9]])
 
243
        self.check_header('100-109', ranges=[[100,109]])
 
244
 
 
245
    def test_range_header_tail(self):
 
246
        self.check_header('-10', tail=10)
 
247
        self.check_header('-50', tail=50)
 
248
 
 
249
    def test_range_header_multi(self):
 
250
        self.check_header('0-9,100-200,300-5000',
 
251
                          ranges=[(0,9), (100, 200), (300,5000)])
 
252
 
 
253
    def test_range_header_mixed(self):
 
254
        self.check_header('0-9,300-5000,-50',
 
255
                          ranges=[(0,9), (300,5000)],
 
256
                          tail=50)
 
257
 
 
258
 
 
259
class TestWallServer(object):
 
260
    """Tests exceptions during the connection phase"""
 
261
 
 
262
    def create_transport_readonly_server(self):
 
263
        return HttpServer(WallRequestHandler)
 
264
 
 
265
    def test_http_has(self):
 
266
        server = self.get_readonly_server()
 
267
        t = self._transport(server.get_url())
 
268
        self.assertRaises(ConnectionError, t.has, 'foo/bar')
 
269
 
 
270
    def test_http_get(self):
 
271
        server = self.get_readonly_server()
 
272
        t = self._transport(server.get_url())
 
273
        self.assertRaises(ConnectionError, t.get, 'foo/bar')
 
274
 
 
275
 
 
276
class TestWallServer_urllib(TestWallServer, TestCaseWithWebserver):
 
277
    """Tests WallServer for urllib implementation"""
 
278
 
 
279
    _transport = HttpTransport_urllib
 
280
 
 
281
 
 
282
class TestWallServer_pycurl(TestWithTransport_pycurl,
 
283
                            TestWallServer,
 
284
                            TestCaseWithWebserver):
 
285
    """Tests WallServer for pycurl implementation"""
 
286
 
 
287
 
 
288
class TestBadStatusServer(object):
 
289
    """Tests bad status from server."""
 
290
 
 
291
    def create_transport_readonly_server(self):
 
292
        return HttpServer(BadStatusRequestHandler)
 
293
 
 
294
    def test_http_has(self):
 
295
        server = self.get_readonly_server()
 
296
        t = self._transport(server.get_url())
 
297
        self.assertRaises(InvalidHttpResponse, t.has, 'foo/bar')
 
298
 
 
299
    def test_http_get(self):
 
300
        server = self.get_readonly_server()
 
301
        t = self._transport(server.get_url())
 
302
        self.assertRaises(InvalidHttpResponse, t.get, 'foo/bar')
 
303
 
 
304
 
 
305
class TestBadStatusServer_urllib(TestBadStatusServer, TestCaseWithWebserver):
 
306
    """Tests BadStatusServer for urllib implementation"""
 
307
 
 
308
    _transport = HttpTransport_urllib
 
309
 
 
310
 
 
311
class TestBadStatusServer_pycurl(TestWithTransport_pycurl,
 
312
                                 TestBadStatusServer,
 
313
                                 TestCaseWithWebserver):
 
314
    """Tests BadStatusServer for pycurl implementation"""
 
315
 
 
316
 
 
317
class TestInvalidStatusServer(TestBadStatusServer):
 
318
    """Tests invalid status from server.
 
319
 
 
320
    Both implementations raises the same error as for a bad status.
 
321
    """
 
322
 
 
323
    def create_transport_readonly_server(self):
 
324
        return HttpServer(InvalidStatusRequestHandler)
 
325
 
 
326
 
 
327
class TestInvalidStatusServer_urllib(TestInvalidStatusServer,
 
328
                                     TestCaseWithWebserver):
 
329
    """Tests InvalidStatusServer for urllib implementation"""
 
330
 
 
331
    _transport = HttpTransport_urllib
 
332
 
 
333
 
 
334
class TestInvalidStatusServer_pycurl(TestWithTransport_pycurl,
 
335
                                     TestInvalidStatusServer,
 
336
                                     TestCaseWithWebserver):
 
337
    """Tests InvalidStatusServer for pycurl implementation"""
 
338
 
 
339
 
 
340
class TestBadProtocolServer(object):
 
341
    """Tests bad status from server."""
 
342
 
 
343
    def create_transport_readonly_server(self):
 
344
        return HttpServer(BadProtocolRequestHandler)
 
345
 
 
346
    def test_http_has(self):
 
347
        server = self.get_readonly_server()
 
348
        t = self._transport(server.get_url())
 
349
        self.assertRaises(InvalidHttpResponse, t.has, 'foo/bar')
 
350
 
 
351
    def test_http_get(self):
 
352
        server = self.get_readonly_server()
 
353
        t = self._transport(server.get_url())
 
354
        self.assertRaises(InvalidHttpResponse, t.get, 'foo/bar')
 
355
 
 
356
 
 
357
class TestBadProtocolServer_urllib(TestBadProtocolServer,
 
358
                                   TestCaseWithWebserver):
 
359
    """Tests BadProtocolServer for urllib implementation"""
 
360
 
 
361
    _transport = HttpTransport_urllib
 
362
 
 
363
# curl don't check the protocol version
 
364
#class TestBadProtocolServer_pycurl(TestWithTransport_pycurl,
 
365
#                                   TestBadProtocolServer,
 
366
#                                   TestCaseWithWebserver):
 
367
#    """Tests BadProtocolServer for pycurl implementation"""
 
368
 
 
369
 
 
370
class TestRangesServer(object):
 
371
    """Tests range requests against a server.
 
372
 
 
373
    This MUST be used by daughter classes that also inherit from
 
374
    TestCaseWithWebserver.
 
375
 
 
376
    We can't inherit directly from TestCaseWithWebserver or the
 
377
    test framework will try to create an instance which cannot
 
378
    run, its implementation being incomplete.
 
379
    """
 
380
 
 
381
    def setUp(self):
 
382
        TestCaseWithWebserver.setUp(self)
 
383
        transport = self.get_transport()
 
384
        if transport.is_readonly():
 
385
            file('a', 'w').write('0123456789')
 
386
        else:
 
387
            transport.put_bytes('a', '0123456789')
 
388
 
 
389
    def test_single_range(self):
 
390
        server = self.get_readonly_server()
 
391
        t = self._transport(server.get_url())
 
392
        content = t.readv(_file_10, )
 
393
 
 
394
        self.assertRaises(errors.InvalidRange, out.read, 20)
 
395
 
 
396
        out.seek(100)
 
397
        self.assertEqual(_single_range_response[2], out.read(100))
 
398
 
 
399
    def test_single_range_no_content(self):
 
400
        out = self.get_response(_single_range_no_content_type)
 
401
        self.assertIsInstance(out, response.HttpRangeResponse)
 
402
 
 
403
        self.assertRaises(errors.InvalidRange, out.read, 20)
 
404
 
 
405
        out.seek(100)
 
406
        self.assertEqual(_single_range_no_content_type[2], out.read(100))
 
407
 
 
408
    def test_multi_range(self):
 
409
        out = self.get_response(_multipart_range_response)
 
410
        self.assertIsInstance(out, response.HttpMultipartRangeResponse)
 
411
 
 
412
        # Just make sure we can read the right contents
 
413
        out.seek(0)
 
414
        out.read(255)
 
415
 
 
416
        out.seek(1000)
 
417
        out.read(1050)
 
418
 
 
419
    def test_multi_squid_range(self):
 
420
        out = self.get_response(_multipart_squid_range_response)
 
421
        self.assertIsInstance(out, response.HttpMultipartRangeResponse)
 
422
 
 
423
        # Just make sure we can read the right contents
 
424
        out.seek(0)
 
425
        out.read(100)
 
426
 
 
427
        out.seek(300)
 
428
        out.read(200)
 
429
 
 
430
    def test_full_text_no_content_type(self):
 
431
        # We should not require Content-Type for a full response
 
432
        a_response = _full_text_response
 
433
        headers = http._extract_headers(a_response[1], 'http://foo')
 
434
        del headers['Content-Type']
 
435
        out = response.handle_response('http://foo', a_response[0], headers,
 
436
                                        StringIO(a_response[2]))
 
437
        self.assertEqual(_full_text_response[2], out.read())
 
438
 
 
439
    def test_missing_content_range(self):
 
440
        a_response = _single_range_response
 
441
        headers = http._extract_headers(a_response[1], 'http://nocontent')
 
442
        del headers['Content-Range']
 
443
        self.assertRaises(errors.InvalidHttpResponse,
 
444
            response.handle_response, 'http://nocontent', a_response[0],
 
445
                                      headers, StringIO(a_response[2]))