~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: mbp at sourcefrog
  • Date: 2006-11-21 01:08:52 UTC
  • mfrom: (2004.1.42 bzr.urllib.keepalive)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: mbp@sourcefrog.net-20061121010852-838b560632acc36c
merge urllib keepalive etc

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
21
21
 
22
 
import errno
23
22
import select
24
23
import socket
25
24
import threading
26
25
 
27
26
import bzrlib
28
 
from bzrlib.errors import DependencyNotPresent, UnsupportedProtocol
 
27
from bzrlib import errors
29
28
from bzrlib import osutils
30
 
from bzrlib.tests import TestCase, TestSkipped
31
 
from bzrlib.transport import get_transport, Transport
32
 
from bzrlib.transport.http import extract_auth, HttpTransportBase
 
29
from bzrlib.tests import (
 
30
    TestCase,
 
31
    TestSkipped,
 
32
    )
 
33
from bzrlib.tests.HttpServer import (
 
34
    HttpServer,
 
35
    HttpServer_PyCurl,
 
36
    HttpServer_urllib,
 
37
    )
 
38
from bzrlib.tests.HTTPTestUtil import (
 
39
    BadProtocolRequestHandler,
 
40
    BadStatusRequestHandler,
 
41
    ForbiddenRequestHandler,
 
42
    InvalidStatusRequestHandler,
 
43
    NoRangeRequestHandler,
 
44
    SingleRangeRequestHandler,
 
45
    TestCaseWithWebserver,
 
46
    WallRequestHandler,
 
47
    )
 
48
from bzrlib.transport import (
 
49
    get_transport,
 
50
    Transport,
 
51
    )
 
52
from bzrlib.transport.http import (
 
53
    extract_auth,
 
54
    HttpTransportBase,
 
55
    )
33
56
from bzrlib.transport.http._urllib import HttpTransport_urllib
34
 
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
35
57
 
36
58
 
37
59
class FakeManager(object):
38
60
 
39
61
    def __init__(self):
40
62
        self.credentials = []
41
 
        
 
63
 
42
64
    def add_password(self, realm, host, username, password):
43
65
        self.credentials.append([realm, host, username, password])
44
66
 
99
121
 
100
122
class TestHttpUrls(TestCase):
101
123
 
 
124
    # FIXME: Some of these tests should be done for both
 
125
    # implementations
 
126
 
102
127
    def test_url_parsing(self):
103
128
        f = FakeManager()
104
129
        url = extract_auth('http://example.com', f)
107
132
        url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
108
133
        self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
109
134
        self.assertEquals(1, len(f.credentials))
110
 
        self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'], f.credentials[0])
111
 
        
 
135
        self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
 
136
                          f.credentials[0])
 
137
 
112
138
    def test_abs_url(self):
113
139
        """Construction of absolute http URLs"""
114
140
        t = HttpTransport_urllib('http://bazaar-vcs.org/bzr/bzr.dev/')
115
141
        eq = self.assertEqualDiff
116
142
        eq(t.abspath('.'),
117
143
           'http://bazaar-vcs.org/bzr/bzr.dev')
118
 
        eq(t.abspath('foo/bar'), 
 
144
        eq(t.abspath('foo/bar'),
119
145
           'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
120
146
        eq(t.abspath('.bzr'),
121
147
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
128
154
        self.assertRaises(ValueError,
129
155
            t.abspath,
130
156
            '.bzr/')
 
157
        t = HttpTransport_urllib('http://http://bazaar-vcs.org/bzr/bzr.dev/')
 
158
        self.assertRaises(errors.InvalidURL, t.has, 'foo/bar')
131
159
 
132
160
    def test_http_root_urls(self):
133
161
        """Construction of URLs from server root"""
138
166
 
139
167
    def test_http_impl_urls(self):
140
168
        """There are servers which ask for particular clients to connect"""
 
169
        server = HttpServer_PyCurl()
141
170
        try:
142
 
            from bzrlib.transport.http._pycurl import HttpServer_PyCurl
143
 
            server = HttpServer_PyCurl()
144
 
            try:
145
 
                server.setUp()
146
 
                url = server.get_url()
147
 
                self.assertTrue(url.startswith('http+pycurl://'))
148
 
            finally:
149
 
                server.tearDown()
150
 
        except DependencyNotPresent:
151
 
            raise TestSkipped('pycurl not present')
152
 
 
153
 
 
154
 
class TestHttpMixins(object):
155
 
 
156
 
    def _prep_tree(self):
 
171
            server.setUp()
 
172
            url = server.get_url()
 
173
            self.assertTrue(url.startswith('http+pycurl://'))
 
174
        finally:
 
175
            server.tearDown()
 
176
 
 
177
 
 
178
class TestHttpConnections(object):
 
179
    """Test the http connections.
 
180
 
 
181
    This MUST be used by daughter classes that also inherit from
 
182
    TestCaseWithWebserver.
 
183
 
 
184
    We can't inherit directly from TestCaseWithWebserver or the
 
185
    test framework will try to create an instance which cannot
 
186
    run, its implementation being incomplete.
 
187
    """
 
188
 
 
189
    def setUp(self):
 
190
        TestCaseWithWebserver.setUp(self)
157
191
        self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
158
192
                        transport=self.get_transport())
159
193
 
162
196
        t = self._transport(server.get_url())
163
197
        self.assertEqual(t.has('foo/bar'), True)
164
198
        self.assertEqual(len(server.logs), 1)
165
 
        self.assertContainsRe(server.logs[0], 
 
199
        self.assertContainsRe(server.logs[0],
166
200
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
167
201
 
168
202
    def test_http_has_not_found(self):
169
203
        server = self.get_readonly_server()
170
204
        t = self._transport(server.get_url())
171
205
        self.assertEqual(t.has('not-found'), False)
172
 
        self.assertContainsRe(server.logs[1], 
 
206
        self.assertContainsRe(server.logs[1],
173
207
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
174
208
 
175
209
    def test_http_get(self):
181
215
            'contents of foo/bar\n')
182
216
        self.assertEqual(len(server.logs), 1)
183
217
        self.assertTrue(server.logs[0].find(
184
 
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s' % bzrlib.__version__) > -1)
 
218
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
 
219
            % bzrlib.__version__) > -1)
185
220
 
186
221
    def test_get_smart_medium(self):
187
222
        # For HTTP, get_smart_medium should return the transport object.
189
224
        http_transport = self._transport(server.get_url())
190
225
        medium = http_transport.get_smart_medium()
191
226
        self.assertIs(medium, http_transport)
192
 
        
193
 
 
194
 
class TestHttpConnections_urllib(TestCaseWithWebserver, TestHttpMixins):
195
 
 
196
 
    _transport = HttpTransport_urllib
197
 
 
198
 
    def setUp(self):
199
 
        TestCaseWithWebserver.setUp(self)
200
 
        self._prep_tree()
201
227
 
202
228
    def test_has_on_bogus_host(self):
203
 
        import urllib2
204
 
        # Get a random address, so that we can be sure there is no
205
 
        # http handler there.
206
 
        s = socket.socket()
207
 
        s.bind(('localhost', 0))
208
 
        t = self._transport('http://%s:%s/' % s.getsockname())
209
 
        self.assertRaises(urllib2.URLError, t.has, 'foo/bar')
210
 
 
211
 
 
212
 
class TestHttpConnections_pycurl(TestCaseWithWebserver, TestHttpMixins):
 
229
        # Get a free address and don't 'accept' on it, so that we
 
230
        # can be sure there is no http handler there, but set a
 
231
        # reasonable timeout to not slow down tests too much.
 
232
        default_timeout = socket.getdefaulttimeout()
 
233
        try:
 
234
            socket.setdefaulttimeout(2)
 
235
            s = socket.socket()
 
236
            s.bind(('localhost', 0))
 
237
            t = self._transport('http://%s:%s/' % s.getsockname())
 
238
            self.assertRaises(errors.ConnectionError, t.has, 'foo/bar')
 
239
        finally:
 
240
            socket.setdefaulttimeout(default_timeout)
 
241
 
 
242
 
 
243
class TestWithTransport_pycurl(object):
 
244
    """Test case to inherit from if pycurl is present"""
213
245
 
214
246
    def _get_pycurl_maybe(self):
215
247
        try:
216
248
            from bzrlib.transport.http._pycurl import PyCurlTransport
217
249
            return PyCurlTransport
218
 
        except DependencyNotPresent:
 
250
        except errors.DependencyNotPresent:
219
251
            raise TestSkipped('pycurl not present')
220
252
 
221
253
    _transport = property(_get_pycurl_maybe)
222
254
 
223
 
    def setUp(self):
224
 
        TestCaseWithWebserver.setUp(self)
225
 
        self._prep_tree()
 
255
 
 
256
class TestHttpConnections_urllib(TestHttpConnections, TestCaseWithWebserver):
 
257
    """Test http connections with urllib"""
 
258
 
 
259
    _transport = HttpTransport_urllib
 
260
 
 
261
 
 
262
 
 
263
class TestHttpConnections_pycurl(TestWithTransport_pycurl,
 
264
                                 TestHttpConnections,
 
265
                                 TestCaseWithWebserver):
 
266
    """Test http connections with pycurl"""
226
267
 
227
268
 
228
269
class TestHttpTransportRegistration(TestCase):
229
270
    """Test registrations of various http implementations"""
230
271
 
231
272
    def test_http_registered(self):
232
 
        import bzrlib.transport.http._urllib
233
 
        from bzrlib.transport import get_transport
234
273
        # urlllib should always be present
235
274
        t = get_transport('http+urllib://bzr.google.com/')
236
275
        self.assertIsInstance(t, Transport)
237
 
        self.assertIsInstance(t, bzrlib.transport.http._urllib.HttpTransport_urllib)
 
276
        self.assertIsInstance(t, HttpTransport_urllib)
238
277
 
239
278
 
240
279
class TestOffsets(TestCase):
270
309
        url = '%s://%s:%s/' % (scheme, server.host, server.port)
271
310
        try:
272
311
            http_transport = get_transport(url)
273
 
        except UnsupportedProtocol:
 
312
        except errors.UnsupportedProtocol:
274
313
            raise TestSkipped('%s not available' % scheme)
275
314
        code, response = http_transport._post('abc def end-of-body')
276
315
        self.assertTrue(
313
352
                          ranges=[(0,9), (300,5000)],
314
353
                          tail=50)
315
354
 
316
 
        
 
355
 
 
356
class TestWallServer(object):
 
357
    """Tests exceptions during the connection phase"""
 
358
 
 
359
    def create_transport_readonly_server(self):
 
360
        return HttpServer(WallRequestHandler)
 
361
 
 
362
    def test_http_has(self):
 
363
        server = self.get_readonly_server()
 
364
        t = self._transport(server.get_url())
 
365
        # Unfortunately httplib (see HTTPResponse._read_status
 
366
        # for details) make no distinction between a closed
 
367
        # socket and badly formatted status line, so we can't
 
368
        # just test for ConnectionError, we have to test
 
369
        # InvalidHttpResponse too.
 
370
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
 
371
                          t.has, 'foo/bar')
 
372
 
 
373
    def test_http_get(self):
 
374
        server = self.get_readonly_server()
 
375
        t = self._transport(server.get_url())
 
376
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
 
377
                          t.get, 'foo/bar')
 
378
 
 
379
 
 
380
class TestWallServer_urllib(TestWallServer, TestCaseWithWebserver):
 
381
    """Tests "wall" server for urllib implementation"""
 
382
 
 
383
    _transport = HttpTransport_urllib
 
384
 
 
385
 
 
386
class TestWallServer_pycurl(TestWithTransport_pycurl,
 
387
                            TestWallServer,
 
388
                            TestCaseWithWebserver):
 
389
    """Tests "wall" server for pycurl implementation"""
 
390
 
 
391
 
 
392
class TestBadStatusServer(object):
 
393
    """Tests bad status from server."""
 
394
 
 
395
    def create_transport_readonly_server(self):
 
396
        return HttpServer(BadStatusRequestHandler)
 
397
 
 
398
    def test_http_has(self):
 
399
        server = self.get_readonly_server()
 
400
        t = self._transport(server.get_url())
 
401
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
 
402
 
 
403
    def test_http_get(self):
 
404
        server = self.get_readonly_server()
 
405
        t = self._transport(server.get_url())
 
406
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
 
407
 
 
408
 
 
409
class TestBadStatusServer_urllib(TestBadStatusServer, TestCaseWithWebserver):
 
410
    """Tests bad status server for urllib implementation"""
 
411
 
 
412
    _transport = HttpTransport_urllib
 
413
 
 
414
 
 
415
class TestBadStatusServer_pycurl(TestWithTransport_pycurl,
 
416
                                 TestBadStatusServer,
 
417
                                 TestCaseWithWebserver):
 
418
    """Tests bad status server for pycurl implementation"""
 
419
 
 
420
 
 
421
class TestInvalidStatusServer(TestBadStatusServer):
 
422
    """Tests invalid status from server.
 
423
 
 
424
    Both implementations raises the same error as for a bad status.
 
425
    """
 
426
 
 
427
    def create_transport_readonly_server(self):
 
428
        return HttpServer(InvalidStatusRequestHandler)
 
429
 
 
430
 
 
431
class TestInvalidStatusServer_urllib(TestInvalidStatusServer,
 
432
                                     TestCaseWithWebserver):
 
433
    """Tests invalid status server for urllib implementation"""
 
434
 
 
435
    _transport = HttpTransport_urllib
 
436
 
 
437
 
 
438
class TestInvalidStatusServer_pycurl(TestWithTransport_pycurl,
 
439
                                     TestInvalidStatusServer,
 
440
                                     TestCaseWithWebserver):
 
441
    """Tests invalid status server for pycurl implementation"""
 
442
 
 
443
 
 
444
class TestBadProtocolServer(object):
 
445
    """Tests bad protocol from server."""
 
446
 
 
447
    def create_transport_readonly_server(self):
 
448
        return HttpServer(BadProtocolRequestHandler)
 
449
 
 
450
    def test_http_has(self):
 
451
        server = self.get_readonly_server()
 
452
        t = self._transport(server.get_url())
 
453
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
 
454
 
 
455
    def test_http_get(self):
 
456
        server = self.get_readonly_server()
 
457
        t = self._transport(server.get_url())
 
458
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
 
459
 
 
460
 
 
461
class TestBadProtocolServer_urllib(TestBadProtocolServer,
 
462
                                   TestCaseWithWebserver):
 
463
    """Tests bad protocol server for urllib implementation"""
 
464
 
 
465
    _transport = HttpTransport_urllib
 
466
 
 
467
# curl don't check the protocol version
 
468
#class TestBadProtocolServer_pycurl(TestWithTransport_pycurl,
 
469
#                                   TestBadProtocolServer,
 
470
#                                   TestCaseWithWebserver):
 
471
#    """Tests bad protocol server for pycurl implementation"""
 
472
 
 
473
 
 
474
class TestForbiddenServer(object):
 
475
    """Tests forbidden server"""
 
476
 
 
477
    def create_transport_readonly_server(self):
 
478
        return HttpServer(ForbiddenRequestHandler)
 
479
 
 
480
    def test_http_has(self):
 
481
        server = self.get_readonly_server()
 
482
        t = self._transport(server.get_url())
 
483
        self.assertRaises(errors.TransportError, t.has, 'foo/bar')
 
484
 
 
485
    def test_http_get(self):
 
486
        server = self.get_readonly_server()
 
487
        t = self._transport(server.get_url())
 
488
        self.assertRaises(errors.TransportError, t.get, 'foo/bar')
 
489
 
 
490
 
 
491
class TestForbiddenServer_urllib(TestForbiddenServer, TestCaseWithWebserver):
 
492
    """Tests forbidden server for urllib implementation"""
 
493
 
 
494
    _transport = HttpTransport_urllib
 
495
 
 
496
 
 
497
class TestForbiddenServer_pycurl(TestWithTransport_pycurl,
 
498
                                 TestForbiddenServer,
 
499
                                 TestCaseWithWebserver):
 
500
    """Tests forbidden server for pycurl implementation"""
 
501
 
 
502
 
317
503
class TestRecordingServer(TestCase):
318
504
 
319
505
    def test_create(self):
343
529
        self.assertEqual('HTTP/1.1 200 OK\r\n',
344
530
                         osutils.recv_all(sock, 4096))
345
531
        self.assertEqual('abc', server.received_bytes)
 
532
 
 
533
 
 
534
class TestRangeRequestServer(object):
 
535
    """Test the http connections.
 
536
 
 
537
    This MUST be used by daughter classes that also inherit from
 
538
    TestCaseWithWebserver.
 
539
 
 
540
    We can't inherit directly from TestCaseWithWebserver or the
 
541
    test framework will try to create an instance which cannot
 
542
    run, its implementation being incomplete.
 
543
    """
 
544
 
 
545
    def setUp(self):
 
546
        TestCaseWithWebserver.setUp(self)
 
547
        self.build_tree_contents([('a', '0123456789')],)
 
548
 
 
549
    """Tests readv requests against server"""
 
550
 
 
551
    def test_readv(self):
 
552
        server = self.get_readonly_server()
 
553
        t = self._transport(server.get_url())
 
554
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
 
555
        self.assertEqual(l[0], (0, '0'))
 
556
        self.assertEqual(l[1], (1, '1'))
 
557
        self.assertEqual(l[2], (3, '34'))
 
558
        self.assertEqual(l[3], (9, '9'))
 
559
 
 
560
    def test_readv_out_of_order(self):
 
561
        server = self.get_readonly_server()
 
562
        t = self._transport(server.get_url())
 
563
        l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
 
564
        self.assertEqual(l[0], (1, '1'))
 
565
        self.assertEqual(l[1], (9, '9'))
 
566
        self.assertEqual(l[2], (0, '0'))
 
567
        self.assertEqual(l[3], (3, '34'))
 
568
 
 
569
    def test_readv_short_read(self):
 
570
        server = self.get_readonly_server()
 
571
        t = self._transport(server.get_url())
 
572
 
 
573
        # This is intentionally reading off the end of the file
 
574
        # since we are sure that it cannot get there
 
575
        self.assertListRaises((errors.ShortReadvError, AssertionError),
 
576
                              t.readv, 'a', [(1,1), (8,10)])
 
577
 
 
578
        # This is trying to seek past the end of the file, it should
 
579
        # also raise a special error
 
580
        self.assertListRaises(errors.ShortReadvError,
 
581
                              t.readv, 'a', [(12,2)])
 
582
 
 
583
 
 
584
class TestSingleRangeRequestServer(TestRangeRequestServer):
 
585
    """Test readv against a server which accept only single range requests"""
 
586
 
 
587
    def create_transport_readonly_server(self):
 
588
        return HttpServer(SingleRangeRequestHandler)
 
589
 
 
590
 
 
591
class TestSingleRangeRequestServer_urllib(TestSingleRangeRequestServer,
 
592
                                          TestCaseWithWebserver):
 
593
    """Tests single range requests accepting server for urllib implementation"""
 
594
 
 
595
    _transport = HttpTransport_urllib
 
596
 
 
597
 
 
598
class TestSingleRangeRequestServer_pycurl(TestWithTransport_pycurl,
 
599
                                          TestSingleRangeRequestServer,
 
600
                                          TestCaseWithWebserver):
 
601
    """Tests single range requests accepting server for pycurl implementation"""
 
602
 
 
603
 
 
604
class TestNoRangeRequestServer(TestRangeRequestServer):
 
605
    """Test readv against a server which do not accept range requests"""
 
606
 
 
607
    def create_transport_readonly_server(self):
 
608
        return HttpServer(NoRangeRequestHandler)
 
609
 
 
610
 
 
611
class TestNoRangeRequestServer_urllib(TestNoRangeRequestServer,
 
612
                                      TestCaseWithWebserver):
 
613
    """Tests range requests refusing server for urllib implementation"""
 
614
 
 
615
    _transport = HttpTransport_urllib
 
616
 
 
617
 
 
618
class TestNoRangeRequestServer_pycurl(TestWithTransport_pycurl,
 
619
                               TestNoRangeRequestServer,
 
620
                               TestCaseWithWebserver):
 
621
    """Tests range requests refusing server for pycurl implementation"""
 
622
 
 
623