~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-10-11 23:21:22 UTC
  • mfrom: (5462.3.21 597791-http-tests)
  • Revision ID: pqm@pqm.ubuntu.com-20101011232122-g2ejz5grpjes5brf
(mbp) cleanup test_http to use scenarios;
 add load_tests_from_scenarios (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
# TODO: Should be renamed to bzrlib.transport.http.tests?
24
24
# TODO: What about renaming to bzrlib.tests.transport.http ?
25
25
 
26
 
from cStringIO import StringIO
27
26
import httplib
28
 
import os
29
 
import select
30
27
import SimpleHTTPServer
31
28
import socket
32
29
import sys
42
39
    tests,
43
40
    transport,
44
41
    ui,
45
 
    urlutils,
46
42
    )
47
43
from bzrlib.tests import (
48
44
    features,
50
46
    http_utils,
51
47
    test_server,
52
48
    )
 
49
from bzrlib.tests.scenarios import (
 
50
    load_tests_apply_scenarios,
 
51
    multiply_scenarios,
 
52
    )
53
53
from bzrlib.transport import (
54
54
    http,
55
55
    remote,
64
64
    from bzrlib.transport.http._pycurl import PyCurlTransport
65
65
 
66
66
 
67
 
def load_tests(standard_tests, module, loader):
68
 
    """Multiply tests for http clients and protocol versions."""
69
 
    result = loader.suiteClass()
70
 
 
71
 
    # one for each transport implementation
72
 
    t_tests, remaining_tests = tests.split_suite_by_condition(
73
 
        standard_tests, tests.condition_isinstance((
74
 
                TestHttpTransportRegistration,
75
 
                TestHttpTransportUrls,
76
 
                Test_redirected_to,
77
 
                )))
 
67
load_tests = load_tests_apply_scenarios
 
68
 
 
69
 
 
70
def vary_by_http_client_implementation():
 
71
    """Test the two libraries we can use, pycurl and urllib."""
78
72
    transport_scenarios = [
79
73
        ('urllib', dict(_transport=_urllib.HttpTransport_urllib,
80
74
                        _server=http_server.HttpServer_urllib,
85
79
            ('pycurl', dict(_transport=PyCurlTransport,
86
80
                            _server=http_server.HttpServer_PyCurl,
87
81
                            _url_protocol='http+pycurl',)))
88
 
    tests.multiply_tests(t_tests, transport_scenarios, result)
89
 
 
90
 
    protocol_scenarios = [
91
 
            ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
92
 
            ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
93
 
            ]
94
 
 
95
 
    # some tests are parametrized by the protocol version only
96
 
    p_tests, remaining_tests = tests.split_suite_by_condition(
97
 
        remaining_tests, tests.condition_isinstance((
98
 
                TestAuthOnRedirected,
99
 
                )))
100
 
    tests.multiply_tests(p_tests, protocol_scenarios, result)
101
 
 
102
 
    # each implementation tested with each HTTP version
103
 
    tp_tests, remaining_tests = tests.split_suite_by_condition(
104
 
        remaining_tests, tests.condition_isinstance((
105
 
                SmartHTTPTunnellingTest,
106
 
                TestDoCatchRedirections,
107
 
                TestHTTPConnections,
108
 
                TestHTTPRedirections,
109
 
                TestHTTPSilentRedirections,
110
 
                TestLimitedRangeRequestServer,
111
 
                TestPost,
112
 
                TestProxyHttpServer,
113
 
                TestRanges,
114
 
                TestSpecificRequestHandler,
115
 
                )))
116
 
    tp_scenarios = tests.multiply_scenarios(transport_scenarios,
117
 
                                            protocol_scenarios)
118
 
    tests.multiply_tests(tp_tests, tp_scenarios, result)
119
 
 
120
 
    # proxy auth: each auth scheme on all http versions on all implementations.
121
 
    tppa_tests, remaining_tests = tests.split_suite_by_condition(
122
 
        remaining_tests, tests.condition_isinstance((
123
 
                TestProxyAuth,
124
 
                )))
125
 
    proxy_auth_scheme_scenarios = [
 
82
    return transport_scenarios
 
83
 
 
84
 
 
85
def vary_by_http_protocol_version():
 
86
    """Test on http/1.0 and 1.1"""
 
87
    return [
 
88
        ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
 
89
        ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
 
90
        ]
 
91
 
 
92
 
 
93
def vary_by_http_proxy_auth_scheme():
 
94
    return [
126
95
        ('basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
127
96
        ('digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
128
97
        ('basicdigest',
129
 
         dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
 
98
            dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
130
99
        ]
131
 
    tppa_scenarios = tests.multiply_scenarios(tp_scenarios,
132
 
                                              proxy_auth_scheme_scenarios)
133
 
    tests.multiply_tests(tppa_tests, tppa_scenarios, result)
134
 
 
135
 
    # auth: each auth scheme on all http versions on all implementations.
136
 
    tpa_tests, remaining_tests = tests.split_suite_by_condition(
137
 
        remaining_tests, tests.condition_isinstance((
138
 
                TestAuth,
139
 
                )))
140
 
    auth_scheme_scenarios = [
 
100
 
 
101
 
 
102
def vary_by_http_auth_scheme():
 
103
    return [
141
104
        ('basic', dict(_auth_server=http_utils.HTTPBasicAuthServer)),
142
105
        ('digest', dict(_auth_server=http_utils.HTTPDigestAuthServer)),
143
106
        ('basicdigest',
144
 
         dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
 
107
            dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
145
108
        ]
146
 
    tpa_scenarios = tests.multiply_scenarios(tp_scenarios,
147
 
                                             auth_scheme_scenarios)
148
 
    tests.multiply_tests(tpa_tests, tpa_scenarios, result)
149
 
 
150
 
    # activity: on all http[s] versions on all implementations
151
 
    tpact_tests, remaining_tests = tests.split_suite_by_condition(
152
 
        remaining_tests, tests.condition_isinstance((
153
 
                TestActivity,
154
 
                )))
 
109
 
 
110
 
 
111
def vary_by_http_activity():
155
112
    activity_scenarios = [
156
113
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
157
 
                             _transport=_urllib.HttpTransport_urllib,)),
 
114
                            _transport=_urllib.HttpTransport_urllib,)),
158
115
        ]
159
116
    if tests.HTTPSServerFeature.available():
160
117
        activity_scenarios.append(
161
118
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
162
 
                                  _transport=_urllib.HttpTransport_urllib,)),)
 
119
                                _transport=_urllib.HttpTransport_urllib,)),)
163
120
    if features.pycurl.available():
164
121
        activity_scenarios.append(
165
122
            ('pycurl,http', dict(_activity_server=ActivityHTTPServer,
166
 
                                 _transport=PyCurlTransport,)),)
 
123
                                _transport=PyCurlTransport,)),)
167
124
        if tests.HTTPSServerFeature.available():
168
125
            from bzrlib.tests import (
169
126
                ssl_certs,
181
138
 
182
139
            activity_scenarios.append(
183
140
                ('pycurl,https', dict(_activity_server=ActivityHTTPSServer,
184
 
                                      _transport=HTTPS_pycurl_transport,)),)
185
 
 
186
 
    tpact_scenarios = tests.multiply_scenarios(activity_scenarios,
187
 
                                               protocol_scenarios)
188
 
    tests.multiply_tests(tpact_tests, tpact_scenarios, result)
189
 
 
190
 
    # No parametrization for the remaining tests
191
 
    result.addTests(remaining_tests)
192
 
 
193
 
    return result
 
141
                                    _transport=HTTPS_pycurl_transport,)),)
 
142
    return activity_scenarios
194
143
 
195
144
 
196
145
class FakeManager(object):
401
350
class TestHttpTransportUrls(tests.TestCase):
402
351
    """Test the http urls."""
403
352
 
 
353
    scenarios = vary_by_http_client_implementation()
 
354
 
404
355
    def test_abs_url(self):
405
356
        """Construction of absolute http URLs"""
406
357
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
413
364
 
414
365
    def test_invalid_http_urls(self):
415
366
        """Trap invalid construction of urls"""
416
 
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
 
367
        self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
417
368
        self.assertRaises(errors.InvalidURL,
418
369
                          self._transport,
419
370
                          'http://http://bazaar-vcs.org/bzr/bzr.dev/')
475
426
class TestHTTPConnections(http_utils.TestCaseWithWebserver):
476
427
    """Test the http connections."""
477
428
 
 
429
    scenarios = multiply_scenarios(
 
430
        vary_by_http_client_implementation(), 
 
431
        vary_by_http_protocol_version(),
 
432
        )
 
433
 
478
434
    def setUp(self):
479
435
        http_utils.TestCaseWithWebserver.setUp(self)
480
436
        self.build_tree(['foo/', 'foo/bar'], line_endings='binary',
525
481
class TestHttpTransportRegistration(tests.TestCase):
526
482
    """Test registrations of various http implementations"""
527
483
 
 
484
    scenarios = vary_by_http_client_implementation()
 
485
 
528
486
    def test_http_registered(self):
529
487
        t = transport.get_transport('%s://foo.com/' % self._url_protocol)
530
488
        self.assertIsInstance(t, transport.Transport)
533
491
 
534
492
class TestPost(tests.TestCase):
535
493
 
 
494
    scenarios = multiply_scenarios(
 
495
        vary_by_http_client_implementation(), 
 
496
        vary_by_http_protocol_version(),
 
497
        )
 
498
 
536
499
    def test_post_body_is_received(self):
537
500
        server = RecordingServer(expect_body_tail='end-of-body',
538
501
                                 scheme=self._url_protocol)
585
548
    Daughter classes are expected to override _req_handler_class
586
549
    """
587
550
 
 
551
    scenarios = multiply_scenarios(
 
552
        vary_by_http_client_implementation(), 
 
553
        vary_by_http_protocol_version(),
 
554
        )
 
555
 
588
556
    # Provide a useful default
589
557
    _req_handler_class = http_server.TestingHTTPRequestHandler
590
558
 
841
809
        t = self.get_readonly_transport()
842
810
        # force transport to issue multiple requests
843
811
        t._get_max_size = 2
844
 
        l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
 
812
        list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
845
813
        # The server should have issued 3 requests
846
814
        self.assertEqual(3, server.GET_request_nb)
847
815
        self.assertEqual('0123456789', t.get_bytes('a'))
924
892
    def get_multiple_ranges(self, file, file_size, ranges):
925
893
        self.send_response(206)
926
894
        self.send_header('Accept-Ranges', 'bytes')
 
895
        # XXX: this is strange; the 'random' name below seems undefined and
 
896
        # yet the tests pass -- mbp 2010-10-11 bug 658773
927
897
        boundary = "%d" % random.randint(0,0x7FFFFFFF)
928
898
        self.send_header("Content-Type",
929
899
                         "multipart/byteranges; boundary=%s" % boundary)
1055
1025
class TestLimitedRangeRequestServer(http_utils.TestCaseWithWebserver):
1056
1026
    """Tests readv requests against a server erroring out on too much ranges."""
1057
1027
 
 
1028
    scenarios = multiply_scenarios(
 
1029
        vary_by_http_client_implementation(), 
 
1030
        vary_by_http_protocol_version(),
 
1031
        )
 
1032
 
1058
1033
    # Requests with more range specifiers will error out
1059
1034
    range_limit = 3
1060
1035
 
1134
1109
    to the file names).
1135
1110
    """
1136
1111
 
 
1112
    scenarios = multiply_scenarios(
 
1113
        vary_by_http_client_implementation(), 
 
1114
        vary_by_http_protocol_version(),
 
1115
        )
 
1116
 
1137
1117
    # FIXME: We don't have an https server available, so we don't
1138
1118
    # test https connections. --vila toolongago
1139
1119
 
1236
1216
class TestRanges(http_utils.TestCaseWithWebserver):
1237
1217
    """Test the Range header in GET methods."""
1238
1218
 
 
1219
    scenarios = multiply_scenarios(
 
1220
        vary_by_http_client_implementation(), 
 
1221
        vary_by_http_protocol_version(),
 
1222
        )
 
1223
 
1239
1224
    def setUp(self):
1240
1225
        http_utils.TestCaseWithWebserver.setUp(self)
1241
1226
        self.build_tree_contents([('a', '0123456789')],)
1281
1266
class TestHTTPRedirections(http_utils.TestCaseWithRedirectedWebserver):
1282
1267
    """Test redirection between http servers."""
1283
1268
 
 
1269
    scenarios = multiply_scenarios(
 
1270
        vary_by_http_client_implementation(), 
 
1271
        vary_by_http_protocol_version(),
 
1272
        )
 
1273
 
1284
1274
    def setUp(self):
1285
1275
        super(TestHTTPRedirections, self).setUp()
1286
1276
        self.build_tree_contents([('a', '0123456789'),
1349
1339
    -- vila 20070212
1350
1340
    """
1351
1341
 
 
1342
    scenarios = multiply_scenarios(
 
1343
        vary_by_http_client_implementation(), 
 
1344
        vary_by_http_protocol_version(),
 
1345
        )
 
1346
 
1352
1347
    def setUp(self):
1353
1348
        if (features.pycurl.available()
1354
1349
            and self._transport == PyCurlTransport):
1399
1394
class TestDoCatchRedirections(http_utils.TestCaseWithRedirectedWebserver):
1400
1395
    """Test transport.do_catching_redirections."""
1401
1396
 
 
1397
    scenarios = multiply_scenarios(
 
1398
        vary_by_http_client_implementation(), 
 
1399
        vary_by_http_protocol_version(),
 
1400
        )
 
1401
 
1402
1402
    def setUp(self):
1403
1403
        super(TestDoCatchRedirections, self).setUp()
1404
1404
        self.build_tree_contents([('a', '0123456789'),],)
1446
1446
class TestAuth(http_utils.TestCaseWithWebserver):
1447
1447
    """Test authentication scheme"""
1448
1448
 
 
1449
    scenarios = multiply_scenarios(
 
1450
        vary_by_http_client_implementation(),
 
1451
        vary_by_http_protocol_version(),
 
1452
        vary_by_http_auth_scheme(),
 
1453
        )
 
1454
 
1449
1455
    _auth_header = 'Authorization'
1450
1456
    _password_prompt_prefix = ''
1451
1457
    _username_prompt_prefix = ''
1655
1661
class TestProxyAuth(TestAuth):
1656
1662
    """Test proxy authentication schemes."""
1657
1663
 
 
1664
    scenarios = multiply_scenarios(
 
1665
        vary_by_http_client_implementation(),
 
1666
        vary_by_http_protocol_version(),
 
1667
        vary_by_http_proxy_auth_scheme(),
 
1668
        )
 
1669
 
1658
1670
    _auth_header = 'Proxy-authorization'
1659
1671
    _password_prompt_prefix = 'Proxy '
1660
1672
    _username_prompt_prefix = 'Proxy '
1716
1728
 
1717
1729
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1718
1730
 
 
1731
    scenarios = multiply_scenarios(
 
1732
        vary_by_http_client_implementation(), 
 
1733
        vary_by_http_protocol_version(),
 
1734
        )
 
1735
 
1719
1736
    def setUp(self):
1720
1737
        super(SmartHTTPTunnellingTest, self).setUp()
1721
1738
        # We use the VFS layer as part of HTTP tunnelling tests.
1810
1827
 
1811
1828
class Test_redirected_to(tests.TestCase):
1812
1829
 
 
1830
    scenarios = vary_by_http_client_implementation()
 
1831
 
1813
1832
    def test_redirected_to_subdir(self):
1814
1833
        t = self._transport('http://www.example.com/foo')
1815
1834
        r = t._redirected_to('http://www.example.com/foo',
2061
2080
 
2062
2081
class TestActivity(tests.TestCase, TestActivityMixin):
2063
2082
 
 
2083
    scenarios = multiply_scenarios(
 
2084
        vary_by_http_activity(),
 
2085
        vary_by_http_protocol_version(),
 
2086
        )
 
2087
 
2064
2088
    def setUp(self):
2065
2089
        TestActivityMixin.setUp(self)
2066
2090
 
2087
2111
class TestAuthOnRedirected(http_utils.TestCaseWithRedirectedWebserver):
2088
2112
    """Test authentication on the redirected http server."""
2089
2113
 
 
2114
    scenarios = vary_by_http_protocol_version()
 
2115
 
2090
2116
    _auth_header = 'Authorization'
2091
2117
    _password_prompt_prefix = ''
2092
2118
    _username_prompt_prefix = ''