/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
1
# Copyright (C) 2005, 2006 Canonical Ltd
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
2
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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.
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
7
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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.
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
12
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
16
1540.3.3 by Martin Pool
Review updates of pycurl transport
17
# FIXME: This test should be repeated for each available http client
18
# implementation; at the moment we have urllib and pycurl.
19
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
21
# TODO: What about renaming to bzrlib.tests.transport.http ?
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
22
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
23
from cStringIO import StringIO
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
24
import os
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
25
import select
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
26
import socket
2420.1.20 by Vincent Ladeuil
Fix test failure on pqm.
27
import sys
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
28
import threading
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
29
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
30
import bzrlib
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
31
from bzrlib import (
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
32
    config,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
33
    errors,
34
    osutils,
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
35
    tests,
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
36
    ui,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
37
    urlutils,
38
    )
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
39
from bzrlib.tests.HttpServer import (
40
    HttpServer,
41
    HttpServer_PyCurl,
42
    HttpServer_urllib,
43
    )
44
from bzrlib.tests.HTTPTestUtil import (
45
    BadProtocolRequestHandler,
46
    BadStatusRequestHandler,
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
47
    ForbiddenRequestHandler,
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
48
    HTTPBasicAuthServer,
49
    HTTPDigestAuthServer,
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
50
    HTTPServerRedirecting,
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
51
    InvalidStatusRequestHandler,
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
52
    LimitedRangeHTTPServer,
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
53
    NoRangeRequestHandler,
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
54
    ProxyBasicAuthServer,
55
    ProxyDigestAuthServer,
56
    ProxyServer,
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
57
    SingleRangeRequestHandler,
2481.3.1 by Vincent Ladeuil
Fix bug #112719 by using the right range header.
58
    SingleOnlyRangeRequestHandler,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
59
    TestCaseWithRedirectedWebserver,
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
60
    TestCaseWithTwoWebservers,
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
61
    TestCaseWithWebserver,
62
    WallRequestHandler,
63
    )
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
64
from bzrlib.transport import (
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
65
    _CoalescedOffset,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
66
    do_catching_redirections,
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
67
    get_transport,
68
    Transport,
69
    )
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
70
from bzrlib.transport.http import (
71
    extract_auth,
72
    HttpTransportBase,
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
73
    _urllib2_wrappers,
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
74
    )
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
75
from bzrlib.transport.http._urllib import HttpTransport_urllib
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
76
from bzrlib.transport.http._urllib2_wrappers import (
77
    ProxyHandler,
78
    Request,
79
    )
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
80
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
81
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
82
class FakeManager(object):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
83
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
84
    def __init__(self):
85
        self.credentials = []
2004.3.1 by vila
Test ConnectionError exceptions.
86
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
87
    def add_password(self, realm, host, username, password):
88
        self.credentials.append([realm, host, username, password])
89
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
90
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
91
class RecordingServer(object):
92
    """A fake HTTP server.
93
    
94
    It records the bytes sent to it, and replies with a 200.
95
    """
96
97
    def __init__(self, expect_body_tail=None):
2018.2.28 by Andrew Bennetts
Changes in response to review: re-use _base_curl, rather than keeping a seperate _post_curl object; add docstring to test_http.RecordingServer, set is_user_error on some new exceptions.
98
        """Constructor.
99
100
        :type expect_body_tail: str
101
        :param expect_body_tail: a reply won't be sent until this string is
102
            received.
103
        """
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
104
        self._expect_body_tail = expect_body_tail
105
        self.host = None
106
        self.port = None
107
        self.received_bytes = ''
108
109
    def setUp(self):
110
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
111
        self._sock.bind(('127.0.0.1', 0))
112
        self.host, self.port = self._sock.getsockname()
113
        self._ready = threading.Event()
114
        self._thread = threading.Thread(target=self._accept_read_and_reply)
115
        self._thread.setDaemon(True)
116
        self._thread.start()
117
        self._ready.wait(5)
118
119
    def _accept_read_and_reply(self):
120
        self._sock.listen(1)
121
        self._ready.set()
122
        self._sock.settimeout(5)
123
        try:
124
            conn, address = self._sock.accept()
125
            # On win32, the accepted connection will be non-blocking to start
126
            # with because we're using settimeout.
127
            conn.setblocking(True)
128
            while not self.received_bytes.endswith(self._expect_body_tail):
129
                self.received_bytes += conn.recv(4096)
130
            conn.sendall('HTTP/1.1 200 OK\r\n')
131
        except socket.timeout:
132
            # Make sure the client isn't stuck waiting for us to e.g. accept.
133
            self._sock.close()
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
134
        except socket.error:
135
            # The client may have already closed the socket.
136
            pass
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
137
138
    def tearDown(self):
139
        try:
140
            self._sock.close()
141
        except socket.error:
142
            # We might have already closed it.  We don't care.
143
            pass
144
        self.host = None
145
        self.port = None
146
147
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
148
class TestWithTransport_pycurl(object):
149
    """Test case to inherit from if pycurl is present"""
150
151
    def _get_pycurl_maybe(self):
152
        try:
153
            from bzrlib.transport.http._pycurl import PyCurlTransport
154
            return PyCurlTransport
155
        except errors.DependencyNotPresent:
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
156
            raise tests.TestSkipped('pycurl not present')
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
157
158
    _transport = property(_get_pycurl_maybe)
159
160
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
161
class TestHttpUrls(tests.TestCase):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
162
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
163
    # TODO: This should be moved to authorization tests once they
164
    # are written.
2004.1.40 by v.ladeuil+lp at free
Fix the race condition again and correct some small typos to be in
165
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
166
    def test_url_parsing(self):
167
        f = FakeManager()
168
        url = extract_auth('http://example.com', f)
169
        self.assertEquals('http://example.com', url)
170
        self.assertEquals(0, len(f.credentials))
1185.50.94 by John Arbash Meinel
Updated web page url to http://bazaar-vcs.org
171
        url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
172
        self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
173
        self.assertEquals(1, len(f.credentials))
2004.3.1 by vila
Test ConnectionError exceptions.
174
        self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
175
                          f.credentials[0])
176
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
177
178
class TestHttpTransportUrls(object):
179
    """Test the http urls.
180
181
    This MUST be used by daughter classes that also inherit from
182
    TestCase.
183
184
    We can't inherit directly from TestCase or the
185
    test framework will try to create an instance which cannot
186
    run, its implementation being incomplete.
187
    """
188
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
189
    def test_abs_url(self):
190
        """Construction of absolute http URLs"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
191
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
192
        eq = self.assertEqualDiff
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
193
        eq(t.abspath('.'), 'http://bazaar-vcs.org/bzr/bzr.dev')
194
        eq(t.abspath('foo/bar'), 'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
195
        eq(t.abspath('.bzr'), 'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
196
        eq(t.abspath('.bzr/1//2/./3'),
1185.50.94 by John Arbash Meinel
Updated web page url to http://bazaar-vcs.org
197
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
198
199
    def test_invalid_http_urls(self):
200
        """Trap invalid construction of urls"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
201
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
202
        self.assertRaises(errors.InvalidURL,
2485.8.24 by Vincent Ladeuil
Finish http refactoring. Test suite passing.
203
                          self._transport,
204
                          'http://http://bazaar-vcs.org/bzr/bzr.dev/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
205
206
    def test_http_root_urls(self):
207
        """Construction of URLs from server root"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
208
        t = self._transport('http://bzr.ozlabs.org/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
209
        eq = self.assertEqualDiff
210
        eq(t.abspath('.bzr/tree-version'),
211
           'http://bzr.ozlabs.org/.bzr/tree-version')
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
212
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
213
    def test_http_impl_urls(self):
214
        """There are servers which ask for particular clients to connect"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
215
        server = self._server()
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
216
        try:
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
217
            server.setUp()
218
            url = server.get_url()
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
219
            self.assertTrue(url.startswith('%s://' % self._qualified_prefix))
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
220
        finally:
221
            server.tearDown()
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
222
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
223
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
224
class TestHttpUrls_urllib(TestHttpTransportUrls, tests.TestCase):
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
225
    """Test http urls with urllib"""
226
227
    _transport = HttpTransport_urllib
228
    _server = HttpServer_urllib
229
    _qualified_prefix = 'http+urllib'
230
231
232
class TestHttpUrls_pycurl(TestWithTransport_pycurl, TestHttpTransportUrls,
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
233
                          tests.TestCase):
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
234
    """Test http urls with pycurl"""
235
236
    _server = HttpServer_PyCurl
237
    _qualified_prefix = 'http+pycurl'
238
239
    # TODO: This should really be moved into another pycurl
240
    # specific test. When https tests will be implemented, take
241
    # this one into account.
242
    def test_pycurl_without_https_support(self):
243
        """Test that pycurl without SSL do not fail with a traceback.
244
245
        For the purpose of the test, we force pycurl to ignore
246
        https by supplying a fake version_info that do not
247
        support it.
248
        """
249
        try:
250
            import pycurl
251
        except ImportError:
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
252
            raise tests.TestSkipped('pycurl not present')
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
253
        # Now that we have pycurl imported, we can fake its version_info
254
        # This was taken from a windows pycurl without SSL
255
        # (thanks to bialix)
256
        pycurl.version_info = lambda : (2,
257
                                        '7.13.2',
258
                                        462082,
259
                                        'i386-pc-win32',
260
                                        2576,
261
                                        None,
262
                                        0,
263
                                        None,
2294.3.2 by Aaron Bentley
Remove trailing whitespace
264
                                        ('ftp', 'gopher', 'telnet',
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
265
                                         'dict', 'ldap', 'http', 'file'),
266
                                        None,
267
                                        0,
268
                                        None)
269
        self.assertRaises(errors.DependencyNotPresent, self._transport,
270
                          'https://launchpad.net')
271
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
272
class TestHttpConnections(object):
273
    """Test the http connections.
274
275
    This MUST be used by daughter classes that also inherit from
276
    TestCaseWithWebserver.
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
277
278
    We can't inherit directly from TestCaseWithWebserver or the
279
    test framework will try to create an instance which cannot
280
    run, its implementation being incomplete.
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
281
    """
282
283
    def setUp(self):
284
        TestCaseWithWebserver.setUp(self)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
285
        self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
286
                        transport=self.get_transport())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
287
288
    def test_http_has(self):
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
289
        server = self.get_readonly_server()
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
290
        t = self._transport(server.get_url())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
291
        self.assertEqual(t.has('foo/bar'), True)
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
292
        self.assertEqual(len(server.logs), 1)
2004.3.1 by vila
Test ConnectionError exceptions.
293
        self.assertContainsRe(server.logs[0],
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
294
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
1553.1.5 by James Henstridge
Make HTTP transport has() method do HEAD requests, and update test to
295
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
296
    def test_http_has_not_found(self):
297
        server = self.get_readonly_server()
298
        t = self._transport(server.get_url())
1553.1.5 by James Henstridge
Make HTTP transport has() method do HEAD requests, and update test to
299
        self.assertEqual(t.has('not-found'), False)
2004.3.1 by vila
Test ConnectionError exceptions.
300
        self.assertContainsRe(server.logs[1],
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
301
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
302
303
    def test_http_get(self):
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
304
        server = self.get_readonly_server()
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
305
        t = self._transport(server.get_url())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
306
        fp = t.get('foo/bar')
307
        self.assertEqualDiff(
308
            fp.read(),
1553.1.3 by James Henstridge
Make bzrlib.transport.http.HttpServer output referer and user agent as in
309
            'contents of foo/bar\n')
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
310
        self.assertEqual(len(server.logs), 1)
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
311
        self.assertTrue(server.logs[0].find(
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
312
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
313
            % bzrlib.__version__) > -1)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
314
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
315
    def test_get_smart_medium(self):
316
        # For HTTP, get_smart_medium should return the transport object.
317
        server = self.get_readonly_server()
318
        http_transport = self._transport(server.get_url())
319
        medium = http_transport.get_smart_medium()
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
320
        self.assertIs(medium, http_transport)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
321
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
322
    def test_has_on_bogus_host(self):
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
323
        # Get a free address and don't 'accept' on it, so that we
324
        # can be sure there is no http handler there, but set a
325
        # reasonable timeout to not slow down tests too much.
326
        default_timeout = socket.getdefaulttimeout()
327
        try:
328
            socket.setdefaulttimeout(2)
329
            s = socket.socket()
330
            s.bind(('localhost', 0))
331
            t = self._transport('http://%s:%s/' % s.getsockname())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
332
            self.assertRaises(errors.ConnectionError, t.has, 'foo/bar')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
333
        finally:
334
            socket.setdefaulttimeout(default_timeout)
335
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
336
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
337
class TestHttpConnections_urllib(TestHttpConnections, TestCaseWithWebserver):
338
    """Test http connections with urllib"""
339
340
    _transport = HttpTransport_urllib
341
342
343
344
class TestHttpConnections_pycurl(TestWithTransport_pycurl,
345
                                 TestHttpConnections,
346
                                 TestCaseWithWebserver):
347
    """Test http connections with pycurl"""
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
348
349
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
350
class TestHttpTransportRegistration(tests.TestCase):
1540.3.23 by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl
351
    """Test registrations of various http implementations"""
352
353
    def test_http_registered(self):
354
        # urlllib should always be present
355
        t = get_transport('http+urllib://bzr.google.com/')
356
        self.assertIsInstance(t, Transport)
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
357
        self.assertIsInstance(t, HttpTransport_urllib)
1786.1.23 by John Arbash Meinel
Move offset_to_http_ranges back onto HttpTransportBase, clarify tests.
358
359
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
360
class TestPost(object):
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
361
362
    def _test_post_body_is_received(self, scheme):
363
        server = RecordingServer(expect_body_tail='end-of-body')
364
        server.setUp()
365
        self.addCleanup(server.tearDown)
366
        url = '%s://%s:%s/' % (scheme, server.host, server.port)
367
        try:
368
            http_transport = get_transport(url)
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
369
        except errors.UnsupportedProtocol:
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
370
            raise tests.TestSkipped('%s not available' % scheme)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
371
        code, response = http_transport._post('abc def end-of-body')
372
        self.assertTrue(
373
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
374
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
375
        # The transport should not be assuming that the server can accept
376
        # chunked encoding the first time it connects, because HTTP/1.1, so we
377
        # check for the literal string.
378
        self.assertTrue(
379
            server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
380
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
381
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
382
class TestPost_urllib(tests.TestCase, TestPost):
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
383
    """TestPost for urllib implementation"""
384
385
    _transport = HttpTransport_urllib
386
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
387
    def test_post_body_is_received_urllib(self):
388
        self._test_post_body_is_received('http+urllib')
389
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
390
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
391
class TestPost_pycurl(TestWithTransport_pycurl, tests.TestCase, TestPost):
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
392
    """TestPost for pycurl implementation"""
393
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
394
    def test_post_body_is_received_pycurl(self):
395
        self._test_post_body_is_received('http+pycurl')
396
397
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
398
class TestRangeHeader(tests.TestCase):
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
399
    """Test range_header method"""
400
401
    def check_header(self, value, ranges=[], tail=0):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
402
        offsets = [ (start, end - start + 1) for start, end in ranges]
403
        coalesce = Transport._coalesce_offsets
404
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
405
        range_header = HttpTransportBase._range_header
406
        self.assertEqual(value, range_header(coalesced, tail))
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
407
408
    def test_range_header_single(self):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
409
        self.check_header('0-9', ranges=[(0,9)])
410
        self.check_header('100-109', ranges=[(100,109)])
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
411
412
    def test_range_header_tail(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
413
        self.check_header('-10', tail=10)
414
        self.check_header('-50', tail=50)
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
415
416
    def test_range_header_multi(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
417
        self.check_header('0-9,100-200,300-5000',
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
418
                          ranges=[(0,9), (100, 200), (300,5000)])
419
420
    def test_range_header_mixed(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
421
        self.check_header('0-9,300-5000,-50',
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
422
                          ranges=[(0,9), (300,5000)],
423
                          tail=50)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
424
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
425
426
class TestWallServer(object):
427
    """Tests exceptions during the connection phase"""
428
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
429
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
430
        return HttpServer(WallRequestHandler)
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
431
432
    def test_http_has(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
433
        server = self.get_readonly_server()
2004.3.1 by vila
Test ConnectionError exceptions.
434
        t = self._transport(server.get_url())
2004.1.40 by v.ladeuil+lp at free
Fix the race condition again and correct some small typos to be in
435
        # Unfortunately httplib (see HTTPResponse._read_status
436
        # for details) make no distinction between a closed
437
        # socket and badly formatted status line, so we can't
438
        # just test for ConnectionError, we have to test
439
        # InvalidHttpResponse too.
440
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
441
                          t.has, 'foo/bar')
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
442
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
443
    def test_http_get(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
444
        server = self.get_readonly_server()
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
445
        t = self._transport(server.get_url())
2145.1.1 by mbp at sourcefrog
merge urllib keepalive etc
446
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
447
                          t.get, 'foo/bar')
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
448
449
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
450
class TestWallServer_urllib(TestWallServer, TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
451
    """Tests "wall" server for urllib implementation"""
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
452
453
    _transport = HttpTransport_urllib
454
455
456
class TestWallServer_pycurl(TestWithTransport_pycurl,
457
                            TestWallServer,
458
                            TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
459
    """Tests "wall" server for pycurl implementation"""
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
460
461
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
462
class TestBadStatusServer(object):
463
    """Tests bad status from server."""
464
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
465
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
466
        return HttpServer(BadStatusRequestHandler)
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
467
468
    def test_http_has(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
469
        server = self.get_readonly_server()
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
470
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
471
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
472
473
    def test_http_get(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
474
        server = self.get_readonly_server()
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
475
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
476
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
477
478
479
class TestBadStatusServer_urllib(TestBadStatusServer, TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
480
    """Tests bad status server for urllib implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
481
482
    _transport = HttpTransport_urllib
483
484
485
class TestBadStatusServer_pycurl(TestWithTransport_pycurl,
486
                                 TestBadStatusServer,
487
                                 TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
488
    """Tests bad status server for pycurl implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
489
490
491
class TestInvalidStatusServer(TestBadStatusServer):
492
    """Tests invalid status from server.
493
494
    Both implementations raises the same error as for a bad status.
495
    """
496
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
497
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
498
        return HttpServer(InvalidStatusRequestHandler)
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
499
500
501
class TestInvalidStatusServer_urllib(TestInvalidStatusServer,
502
                                     TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
503
    """Tests invalid status server for urllib implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
504
505
    _transport = HttpTransport_urllib
506
507
508
class TestInvalidStatusServer_pycurl(TestWithTransport_pycurl,
509
                                     TestInvalidStatusServer,
510
                                     TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
511
    """Tests invalid status server for pycurl implementation"""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
512
513
514
class TestBadProtocolServer(object):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
515
    """Tests bad protocol from server."""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
516
517
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
518
        return HttpServer(BadProtocolRequestHandler)
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
519
520
    def test_http_has(self):
521
        server = self.get_readonly_server()
522
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
523
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
524
525
    def test_http_get(self):
526
        server = self.get_readonly_server()
527
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
528
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
529
530
531
class TestBadProtocolServer_urllib(TestBadProtocolServer,
532
                                   TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
533
    """Tests bad protocol server for urllib implementation"""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
534
535
    _transport = HttpTransport_urllib
536
537
# curl don't check the protocol version
538
#class TestBadProtocolServer_pycurl(TestWithTransport_pycurl,
539
#                                   TestBadProtocolServer,
540
#                                   TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
541
#    """Tests bad protocol server for pycurl implementation"""
542
543
544
class TestForbiddenServer(object):
545
    """Tests forbidden server"""
546
547
    def create_transport_readonly_server(self):
548
        return HttpServer(ForbiddenRequestHandler)
549
550
    def test_http_has(self):
551
        server = self.get_readonly_server()
552
        t = self._transport(server.get_url())
553
        self.assertRaises(errors.TransportError, t.has, 'foo/bar')
554
555
    def test_http_get(self):
556
        server = self.get_readonly_server()
557
        t = self._transport(server.get_url())
558
        self.assertRaises(errors.TransportError, t.get, 'foo/bar')
559
560
561
class TestForbiddenServer_urllib(TestForbiddenServer, TestCaseWithWebserver):
562
    """Tests forbidden server for urllib implementation"""
563
564
    _transport = HttpTransport_urllib
565
566
567
class TestForbiddenServer_pycurl(TestWithTransport_pycurl,
568
                                 TestForbiddenServer,
569
                                 TestCaseWithWebserver):
570
    """Tests forbidden server for pycurl implementation"""
571
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
572
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
573
class TestRecordingServer(tests.TestCase):
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
574
575
    def test_create(self):
576
        server = RecordingServer(expect_body_tail=None)
577
        self.assertEqual('', server.received_bytes)
578
        self.assertEqual(None, server.host)
579
        self.assertEqual(None, server.port)
580
581
    def test_setUp_and_tearDown(self):
582
        server = RecordingServer(expect_body_tail=None)
583
        server.setUp()
584
        try:
585
            self.assertNotEqual(None, server.host)
586
            self.assertNotEqual(None, server.port)
587
        finally:
588
            server.tearDown()
589
        self.assertEqual(None, server.host)
590
        self.assertEqual(None, server.port)
591
592
    def test_send_receive_bytes(self):
593
        server = RecordingServer(expect_body_tail='c')
594
        server.setUp()
595
        self.addCleanup(server.tearDown)
596
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
597
        sock.connect((server.host, server.port))
598
        sock.sendall('abc')
599
        self.assertEqual('HTTP/1.1 200 OK\r\n',
2091.1.1 by Martin Pool
Avoid MSG_WAITALL as it doesn't work on Windows
600
                         osutils.recv_all(sock, 4096))
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
601
        self.assertEqual('abc', server.received_bytes)
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
602
603
604
class TestRangeRequestServer(object):
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
605
    """Tests readv requests against server.
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
606
607
    This MUST be used by daughter classes that also inherit from
608
    TestCaseWithWebserver.
609
610
    We can't inherit directly from TestCaseWithWebserver or the
611
    test framework will try to create an instance which cannot
612
    run, its implementation being incomplete.
613
    """
614
615
    def setUp(self):
616
        TestCaseWithWebserver.setUp(self)
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
617
        self.build_tree_contents([('a', '0123456789')],)
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
618
619
    def test_readv(self):
620
        server = self.get_readonly_server()
621
        t = self._transport(server.get_url())
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
622
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
623
        self.assertEqual(l[0], (0, '0'))
624
        self.assertEqual(l[1], (1, '1'))
625
        self.assertEqual(l[2], (3, '34'))
626
        self.assertEqual(l[3], (9, '9'))
627
628
    def test_readv_out_of_order(self):
629
        server = self.get_readonly_server()
630
        t = self._transport(server.get_url())
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
631
        l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
632
        self.assertEqual(l[0], (1, '1'))
633
        self.assertEqual(l[1], (9, '9'))
634
        self.assertEqual(l[2], (0, '0'))
635
        self.assertEqual(l[3], (3, '34'))
636
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
637
    def test_readv_invalid_ranges(self):
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
638
        server = self.get_readonly_server()
639
        t = self._transport(server.get_url())
640
641
        # This is intentionally reading off the end of the file
642
        # since we are sure that it cannot get there
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
643
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
644
                              t.readv, 'a', [(1,1), (8,10)])
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
645
646
        # This is trying to seek past the end of the file, it should
647
        # also raise a special error
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
648
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
649
                              t.readv, 'a', [(12,2)])
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
650
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
651
    def test_readv_multiple_get_requests(self):
652
        server = self.get_readonly_server()
653
        t = self._transport(server.get_url())
654
        # force transport to issue multiple requests
655
        t._max_readv_combine = 1
656
        t._max_get_ranges = 1
657
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
658
        self.assertEqual(l[0], (0, '0'))
659
        self.assertEqual(l[1], (1, '1'))
660
        self.assertEqual(l[2], (3, '34'))
661
        self.assertEqual(l[3], (9, '9'))
662
        # The server should have issued 4 requests
3059.2.17 by Vincent Ladeuil
Limit GET requests by body size instead of number of ranges.
663
        self.assertEqual(4, server.GET_request_nb)
664
665
    def test_readv_get_max_size(self):
666
        server = self.get_readonly_server()
667
        t = self._transport(server.get_url())
668
        # force transport to issue multiple requests by limiting the number of
669
        # bytes by request. Note that this apply to coalesced offsets only, a
670
        # single range ill keep its size even if bigger than the limit.
671
        t._get_max_size = 2
672
        l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
673
        self.assertEqual(l[0], (0, '0'))
674
        self.assertEqual(l[1], (1, '1'))
675
        self.assertEqual(l[2], (2, '2345'))
676
        self.assertEqual(l[3], (6, '6789'))
677
        # The server should have issued 3 requests
678
        self.assertEqual(3, server.GET_request_nb)
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
679
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
680
681
class TestSingleRangeRequestServer(TestRangeRequestServer):
682
    """Test readv against a server which accept only single range requests"""
683
684
    def create_transport_readonly_server(self):
685
        return HttpServer(SingleRangeRequestHandler)
686
687
688
class TestSingleRangeRequestServer_urllib(TestSingleRangeRequestServer,
689
                                          TestCaseWithWebserver):
690
    """Tests single range requests accepting server for urllib implementation"""
691
692
    _transport = HttpTransport_urllib
693
694
695
class TestSingleRangeRequestServer_pycurl(TestWithTransport_pycurl,
696
                                          TestSingleRangeRequestServer,
697
                                          TestCaseWithWebserver):
698
    """Tests single range requests accepting server for pycurl implementation"""
699
700
2481.3.1 by Vincent Ladeuil
Fix bug #112719 by using the right range header.
701
class TestSingleOnlyRangeRequestServer(TestRangeRequestServer):
702
    """Test readv against a server which only accept single range requests"""
703
704
    def create_transport_readonly_server(self):
705
        return HttpServer(SingleOnlyRangeRequestHandler)
706
707
708
class TestSingleOnlyRangeRequestServer_urllib(TestSingleOnlyRangeRequestServer,
709
                                              TestCaseWithWebserver):
710
    """Tests single range requests accepting server for urllib implementation"""
711
712
    _transport = HttpTransport_urllib
713
714
715
class TestSingleOnlyRangeRequestServer_pycurl(TestWithTransport_pycurl,
716
                                              TestSingleOnlyRangeRequestServer,
717
                                              TestCaseWithWebserver):
718
    """Tests single range requests accepting server for pycurl implementation"""
719
720
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
721
class TestNoRangeRequestServer(TestRangeRequestServer):
722
    """Test readv against a server which do not accept range requests"""
723
724
    def create_transport_readonly_server(self):
725
        return HttpServer(NoRangeRequestHandler)
726
727
728
class TestNoRangeRequestServer_urllib(TestNoRangeRequestServer,
729
                                      TestCaseWithWebserver):
730
    """Tests range requests refusing server for urllib implementation"""
731
732
    _transport = HttpTransport_urllib
733
734
735
class TestNoRangeRequestServer_pycurl(TestWithTransport_pycurl,
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
736
                                      TestNoRangeRequestServer,
737
                                      TestCaseWithWebserver):
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
738
    """Tests range requests refusing server for pycurl implementation"""
739
740
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
741
class TestLimitedRangeRequestServer(object):
742
    """Tests readv requests against server that errors out on too much ranges.
743
744
    This MUST be used by daughter classes that also inherit from
745
    TestCaseWithWebserver.
746
747
    We can't inherit directly from TestCaseWithWebserver or the
748
    test framework will try to create an instance which cannot
749
    run, its implementation being incomplete.
750
    """
751
752
    range_limit = 3
753
754
    def create_transport_readonly_server(self):
755
        # Requests with more range specifiers will error out
756
        return LimitedRangeHTTPServer(range_limit=self.range_limit)
757
758
    def get_transport(self):
759
        return self._transport(self.get_readonly_server().get_url())
760
761
    def setUp(self):
762
        TestCaseWithWebserver.setUp(self)
763
        # We need to manipulate ranges that correspond to real chunks in the
764
        # response, so we build a content appropriately.
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
765
        filler = ''.join(['abcdefghij' for x in range(102)])
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
766
        content = ''.join(['%04d' % v + filler for v in range(16)])
767
        self.build_tree_contents([('a', content)],)
768
769
    def test_few_ranges(self):
770
        t = self.get_transport()
771
        l = list(t.readv('a', ((0, 4), (1024, 4), )))
772
        self.assertEqual(l[0], (0, '0000'))
773
        self.assertEqual(l[1], (1024, '0001'))
774
        self.assertEqual(1, self.get_readonly_server().GET_request_nb)
775
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
776
    def test_more_ranges(self):
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
777
        t = self.get_transport()
778
        l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
779
        self.assertEqual(l[0], (0, '0000'))
780
        self.assertEqual(l[1], (1024, '0001'))
781
        self.assertEqual(l[2], (4096, '0004'))
782
        self.assertEqual(l[3], (8192, '0008'))
783
        # The server will refuse to serve the first request (too much ranges),
784
        # a second request will succeeds.
785
        self.assertEqual(2, self.get_readonly_server().GET_request_nb)
786
787
788
class TestLimitedRangeRequestServer_urllib(TestLimitedRangeRequestServer,
789
                                          TestCaseWithWebserver):
790
    """Tests limited range requests server for urllib implementation"""
791
792
    _transport = HttpTransport_urllib
793
794
795
class TestLimitedRangeRequestServer_pycurl(TestWithTransport_pycurl,
796
                                          TestLimitedRangeRequestServer,
797
                                          TestCaseWithWebserver):
798
    """Tests limited range requests server for pycurl implementation"""
799
800
801
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
802
class TestHttpProxyWhiteBox(tests.TestCase):
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
803
    """Whitebox test proxy http authorization.
804
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
805
    Only the urllib implementation is tested here.
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
806
    """
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
807
808
    def setUp(self):
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
809
        tests.TestCase.setUp(self)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
810
        self._old_env = {}
811
812
    def tearDown(self):
813
        self._restore_env()
814
815
    def _install_env(self, env):
816
        for name, value in env.iteritems():
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
817
            self._old_env[name] = osutils.set_or_unset_env(name, value)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
818
819
    def _restore_env(self):
820
        for name, value in self._old_env.iteritems():
821
            osutils.set_or_unset_env(name, value)
822
823
    def _proxied_request(self):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
824
        handler = ProxyHandler()
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
825
        request = Request('GET','http://baz/buzzle')
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
826
        handler.set_proxy(request, 'http')
827
        return request
828
829
    def test_empty_user(self):
830
        self._install_env({'http_proxy': 'http://bar.com'})
831
        request = self._proxied_request()
832
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
833
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
834
    def test_invalid_proxy(self):
835
        """A proxy env variable without scheme"""
836
        self._install_env({'http_proxy': 'host:1234'})
837
        self.assertRaises(errors.InvalidURL, self._proxied_request)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
838
839
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
840
class TestProxyHttpServer(object):
841
    """Tests proxy server.
842
843
    This MUST be used by daughter classes that also inherit from
844
    TestCaseWithTwoWebservers.
845
846
    We can't inherit directly from TestCaseWithTwoWebservers or
847
    the test framework will try to create an instance which
848
    cannot run, its implementation being incomplete.
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
849
850
    Be aware that we do not setup a real proxy here. Instead, we
2167.3.7 by v.ladeuil+lp at free
Typos corrected.
851
    check that the *connection* goes through the proxy by serving
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
852
    different content (the faked proxy server append '-proxied'
853
    to the file names).
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
854
    """
855
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
856
    # FIXME: We don't have an https server available, so we don't
857
    # test https connections.
858
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
859
    def setUp(self):
860
        TestCaseWithTwoWebservers.setUp(self)
861
        self.build_tree_contents([('foo', 'contents of foo\n'),
862
                                  ('foo-proxied', 'proxied contents of foo\n')])
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
863
        # Let's setup some attributes for tests
864
        self.server = self.get_readonly_server()
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
865
        self.proxy_address = '%s:%d' % (self.server.host, self.server.port)
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
866
        self.no_proxy_host = self.proxy_address
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
867
        # The secondary server is the proxy
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
868
        self.proxy = self.get_secondary_server()
869
        self.proxy_url = self.proxy.get_url()
870
        self._old_env = {}
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
871
872
    def create_transport_secondary_server(self):
873
        """Creates an http server that will serve files with
874
        '-proxied' appended to their names.
875
        """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
876
        return ProxyServer()
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
877
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
878
    def _install_env(self, env):
879
        for name, value in env.iteritems():
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
880
            self._old_env[name] = osutils.set_or_unset_env(name, value)
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
881
882
    def _restore_env(self):
883
        for name, value in self._old_env.iteritems():
884
            osutils.set_or_unset_env(name, value)
885
886
    def proxied_in_env(self, env):
887
        self._install_env(env)
888
        url = self.server.get_url()
889
        t = self._transport(url)
890
        try:
891
            self.assertEqual(t.get('foo').read(), 'proxied contents of foo\n')
892
        finally:
893
            self._restore_env()
894
895
    def not_proxied_in_env(self, env):
896
        self._install_env(env)
897
        url = self.server.get_url()
898
        t = self._transport(url)
899
        try:
900
            self.assertEqual(t.get('foo').read(), 'contents of foo\n')
901
        finally:
902
            self._restore_env()
903
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
904
    def test_http_proxy(self):
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
905
        self.proxied_in_env({'http_proxy': self.proxy_url})
906
907
    def test_HTTP_PROXY(self):
908
        self.proxied_in_env({'HTTP_PROXY': self.proxy_url})
909
910
    def test_all_proxy(self):
911
        self.proxied_in_env({'all_proxy': self.proxy_url})
912
913
    def test_ALL_PROXY(self):
914
        self.proxied_in_env({'ALL_PROXY': self.proxy_url})
915
916
    def test_http_proxy_with_no_proxy(self):
917
        self.not_proxied_in_env({'http_proxy': self.proxy_url,
918
                                 'no_proxy': self.no_proxy_host})
919
920
    def test_HTTP_PROXY_with_NO_PROXY(self):
921
        self.not_proxied_in_env({'HTTP_PROXY': self.proxy_url,
922
                                 'NO_PROXY': self.no_proxy_host})
923
924
    def test_all_proxy_with_no_proxy(self):
925
        self.not_proxied_in_env({'all_proxy': self.proxy_url,
926
                                 'no_proxy': self.no_proxy_host})
927
928
    def test_ALL_PROXY_with_NO_PROXY(self):
929
        self.not_proxied_in_env({'ALL_PROXY': self.proxy_url,
930
                                 'NO_PROXY': self.no_proxy_host})
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
931
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
932
    def test_http_proxy_without_scheme(self):
933
        self.assertRaises(errors.InvalidURL,
934
                          self.proxied_in_env,
935
                          {'http_proxy': self.proxy_address})
936
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
937
938
class TestProxyHttpServer_urllib(TestProxyHttpServer,
939
                                 TestCaseWithTwoWebservers):
940
    """Tests proxy server for urllib implementation"""
941
942
    _transport = HttpTransport_urllib
943
944
945
class TestProxyHttpServer_pycurl(TestWithTransport_pycurl,
946
                                 TestProxyHttpServer,
947
                                 TestCaseWithTwoWebservers):
948
    """Tests proxy server for pycurl implementation"""
949
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
950
    def setUp(self):
951
        TestProxyHttpServer.setUp(self)
952
        # Oh my ! pycurl does not check for the port as part of
953
        # no_proxy :-( So we just test the host part
954
        self.no_proxy_host = 'localhost'
955
956
    def test_HTTP_PROXY(self):
2949.5.2 by Alexander Belchenko
John's review
957
        # pycurl does not check HTTP_PROXY for security reasons
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
958
        # (for use in a CGI context that we do not care
959
        # about. Should we ?)
3052.3.4 by Vincent Ladeuil
Jam's review feeback.
960
        raise tests.TestNotApplicable(
961
            'pycurl does not check HTTP_PROXY for security reasons')
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
962
963
    def test_HTTP_PROXY_with_NO_PROXY(self):
3052.3.4 by Vincent Ladeuil
Jam's review feeback.
964
        raise tests.TestNotApplicable(
965
            'pycurl does not check HTTP_PROXY for security reasons')
2183.1.1 by Aaron Bentley
Make test HTTP server's range handling more spec-compliant (Vincent Ladeuil)
966
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
967
    def test_http_proxy_without_scheme(self):
968
        # pycurl *ignores* invalid proxy env variables. If that
969
        # ever change in the future, this test will fail
970
        # indicating that pycurl do not ignore anymore such
971
        # variables.
972
        self.not_proxied_in_env({'http_proxy': self.proxy_address})
973
2183.1.1 by Aaron Bentley
Make test HTTP server's range handling more spec-compliant (Vincent Ladeuil)
974
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
975
class TestRanges(object):
976
    """Test the Range header in GET methods..
977
978
    This MUST be used by daughter classes that also inherit from
979
    TestCaseWithWebserver.
980
981
    We can't inherit directly from TestCaseWithWebserver or the
982
    test framework will try to create an instance which cannot
983
    run, its implementation being incomplete.
984
    """
985
986
    def setUp(self):
987
        TestCaseWithWebserver.setUp(self)
988
        self.build_tree_contents([('a', '0123456789')],)
989
        server = self.get_readonly_server()
990
        self.transport = self._transport(server.get_url())
991
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
992
    def _file_contents(self, relpath, ranges):
993
        offsets = [ (start, end - start + 1) for start, end in ranges]
994
        coalesce = self.transport._coalesce_offsets
995
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
996
        code, data = self.transport._get(relpath, coalesced)
997
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
998
        for start, end in ranges:
999
            data.seek(start)
1000
            yield data.read(end - start + 1)
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
1001
1002
    def _file_tail(self, relpath, tail_amount):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
1003
        code, data = self.transport._get(relpath, [], tail_amount)
1004
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
3059.2.15 by Vincent Ladeuil
Fix bogus test.
1005
        data.seek(-tail_amount, 2)
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
1006
        return data.read(tail_amount)
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
1007
1008
    def test_range_header(self):
1009
        # Valid ranges
1010
        map(self.assertEqual,['0', '234'],
1011
            list(self._file_contents('a', [(0,0), (2,4)])),)
1012
        # Tail
1013
        self.assertEqual('789', self._file_tail('a', 3))
1014
        # Syntactically invalid range
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
1015
        self.assertListRaises(errors.InvalidHttpRange,
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
1016
                          self._file_contents, 'a', [(4, 3)])
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
1017
        # Semantically invalid range
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
1018
        self.assertListRaises(errors.InvalidHttpRange,
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
1019
                          self._file_contents, 'a', [(42, 128)])
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
1020
1021
1022
class TestRanges_urllib(TestRanges, TestCaseWithWebserver):
1023
    """Test the Range header in GET methods for urllib implementation"""
1024
1025
    _transport = HttpTransport_urllib
1026
1027
1028
class TestRanges_pycurl(TestWithTransport_pycurl,
1029
                        TestRanges,
1030
                        TestCaseWithWebserver):
1031
    """Test the Range header in GET methods for pycurl implementation"""
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1032
1033
2164.2.16 by Vincent Ladeuil
Add tests.
1034
class TestHTTPRedirections(object):
1035
    """Test redirection between http servers.
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1036
1037
    This MUST be used by daughter classes that also inherit from
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1038
    TestCaseWithRedirectedWebserver.
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1039
1040
    We can't inherit directly from TestCaseWithTwoWebservers or the
1041
    test framework will try to create an instance which cannot
1042
    run, its implementation being incomplete. 
1043
    """
1044
1045
    def create_transport_secondary_server(self):
1046
        """Create the secondary server redirecting to the primary server"""
2164.2.16 by Vincent Ladeuil
Add tests.
1047
        new = self.get_readonly_server()
1048
1049
        redirecting = HTTPServerRedirecting()
1050
        redirecting.redirect_to(new.host, new.port)
1051
        return redirecting
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1052
1053
    def setUp(self):
2164.2.16 by Vincent Ladeuil
Add tests.
1054
        super(TestHTTPRedirections, self).setUp()
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1055
        self.build_tree_contents([('a', '0123456789'),
1056
                                  ('bundle',
1057
                                  '# Bazaar revision bundle v0.9\n#\n')
1058
                                  ],)
1059
1060
        self.old_transport = self._transport(self.old_server.get_url())
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1061
1062
    def test_redirected(self):
2164.2.16 by Vincent Ladeuil
Add tests.
1063
        self.assertRaises(errors.RedirectRequested, self.old_transport.get, 'a')
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1064
        t = self._transport(self.new_server.get_url())
1065
        self.assertEqual('0123456789', t.get('a').read())
1066
1067
    def test_read_redirected_bundle_from_url(self):
1068
        from bzrlib.bundle import read_bundle_from_url
1069
        url = self.old_transport.abspath('bundle')
1070
        bundle = read_bundle_from_url(url)
1071
        # If read_bundle_from_url was successful we get an empty bundle
1072
        self.assertEqual([], bundle.revisions)
2164.2.16 by Vincent Ladeuil
Add tests.
1073
1074
1075
class TestHTTPRedirections_urllib(TestHTTPRedirections,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1076
                                  TestCaseWithRedirectedWebserver):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1077
    """Tests redirections for urllib implementation"""
1078
1079
    _transport = HttpTransport_urllib
1080
2164.2.16 by Vincent Ladeuil
Add tests.
1081
1082
1083
class TestHTTPRedirections_pycurl(TestWithTransport_pycurl,
1084
                                  TestHTTPRedirections,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1085
                                  TestCaseWithRedirectedWebserver):
2164.2.16 by Vincent Ladeuil
Add tests.
1086
    """Tests redirections for pycurl implementation"""
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1087
1088
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1089
class RedirectedRequest(Request):
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
1090
    """Request following redirections"""
1091
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1092
    init_orig = Request.__init__
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
1093
1094
    def __init__(self, method, url, *args, **kwargs):
1095
        RedirectedRequest.init_orig(self, method, url, args, kwargs)
1096
        self.follow_redirections = True
1097
1098
1099
class TestHTTPSilentRedirections_urllib(TestCaseWithRedirectedWebserver):
1100
    """Test redirections provided by urllib.
1101
1102
    http implementations do not redirect silently anymore (they
1103
    do not redirect at all in fact). The mechanism is still in
1104
    place at the _urllib2_wrappers.Request level and these tests
1105
    exercise it.
1106
1107
    For the pycurl implementation
1108
    the redirection have been deleted as we may deprecate pycurl
1109
    and I have no place to keep a working implementation.
1110
    -- vila 20070212
1111
    """
1112
1113
    _transport = HttpTransport_urllib
1114
1115
    def setUp(self):
1116
        super(TestHTTPSilentRedirections_urllib, self).setUp()
1117
        self.setup_redirected_request()
1118
        self.addCleanup(self.cleanup_redirected_request)
1119
        self.build_tree_contents([('a','a'),
1120
                                  ('1/',),
1121
                                  ('1/a', 'redirected once'),
1122
                                  ('2/',),
1123
                                  ('2/a', 'redirected twice'),
1124
                                  ('3/',),
1125
                                  ('3/a', 'redirected thrice'),
1126
                                  ('4/',),
1127
                                  ('4/a', 'redirected 4 times'),
1128
                                  ('5/',),
1129
                                  ('5/a', 'redirected 5 times'),
1130
                                  ],)
1131
1132
        self.old_transport = self._transport(self.old_server.get_url())
1133
1134
    def setup_redirected_request(self):
1135
        self.original_class = _urllib2_wrappers.Request
1136
        _urllib2_wrappers.Request = RedirectedRequest
1137
1138
    def cleanup_redirected_request(self):
1139
        _urllib2_wrappers.Request = self.original_class
1140
1141
    def create_transport_secondary_server(self):
1142
        """Create the secondary server, redirections are defined in the tests"""
1143
        return HTTPServerRedirecting()
1144
1145
    def test_one_redirection(self):
1146
        t = self.old_transport
1147
1148
        req = RedirectedRequest('GET', t.abspath('a'))
1149
        req.follow_redirections = True
1150
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1151
                                       self.new_server.port)
1152
        self.old_server.redirections = \
1153
            [('(.*)', r'%s/1\1' % (new_prefix), 301),]
1154
        self.assertEquals('redirected once',t._perform(req).read())
1155
1156
    def test_five_redirections(self):
1157
        t = self.old_transport
1158
1159
        req = RedirectedRequest('GET', t.abspath('a'))
1160
        req.follow_redirections = True
1161
        old_prefix = 'http://%s:%s' % (self.old_server.host,
1162
                                       self.old_server.port)
1163
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1164
                                       self.new_server.port)
1165
        self.old_server.redirections = \
1166
            [('/1(.*)', r'%s/2\1' % (old_prefix), 302),
1167
             ('/2(.*)', r'%s/3\1' % (old_prefix), 303),
1168
             ('/3(.*)', r'%s/4\1' % (old_prefix), 307),
1169
             ('/4(.*)', r'%s/5\1' % (new_prefix), 301),
1170
             ('(/[^/]+)', r'%s/1\1' % (old_prefix), 301),
1171
             ]
1172
        self.assertEquals('redirected 5 times',t._perform(req).read())
1173
1174
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1175
class TestDoCatchRedirections(TestCaseWithRedirectedWebserver):
1176
    """Test transport.do_catching_redirections.
1177
1178
    We arbitrarily choose to use urllib transports
1179
    """
1180
1181
    _transport = HttpTransport_urllib
1182
1183
    def setUp(self):
1184
        super(TestDoCatchRedirections, self).setUp()
1185
        self.build_tree_contents([('a', '0123456789'),],)
1186
1187
        self.old_transport = self._transport(self.old_server.get_url())
1188
1189
    def get_a(self, transport):
1190
        return transport.get('a')
1191
1192
    def test_no_redirection(self):
1193
        t = self._transport(self.new_server.get_url())
1194
1195
        # We use None for redirected so that we fail if redirected
1196
        self.assertEquals('0123456789',
1197
                          do_catching_redirections(self.get_a, t, None).read())
1198
1199
    def test_one_redirection(self):
1200
        self.redirections = 0
1201
1202
        def redirected(transport, exception, redirection_notice):
1203
            self.redirections += 1
1204
            dir, file = urlutils.split(exception.target)
1205
            return self._transport(dir)
1206
1207
        self.assertEquals('0123456789',
1208
                          do_catching_redirections(self.get_a,
1209
                                                   self.old_transport,
1210
                                                   redirected
1211
                                                   ).read())
1212
        self.assertEquals(1, self.redirections)
1213
1214
    def test_redirection_loop(self):
1215
1216
        def redirected(transport, exception, redirection_notice):
1217
            # By using the redirected url as a base dir for the
1218
            # *old* transport, we create a loop: a => a/a =>
1219
            # a/a/a
1220
            return self.old_transport.clone(exception.target)
1221
1222
        self.assertRaises(errors.TooManyRedirections, do_catching_redirections,
1223
                          self.get_a, self.old_transport, redirected)
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1224
1225
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1226
class TestAuth(object):
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1227
    """Test some authentication scheme specified by daughter class.
1228
1229
    This MUST be used by daughter classes that also inherit from
1230
    either TestCaseWithWebserver or TestCaseWithTwoWebservers.
1231
    """
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1232
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1233
    _password_prompt_prefix = ''
1234
2363.4.7 by Vincent Ladeuil
Deeper tests, prepare the auth setting that will avoid the
1235
    def setUp(self):
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1236
        """Set up the test environment
1237
1238
        Daughter classes should set up their own environment
1239
        (including self.server) and explicitely call this
1240
        method. This is needed because we want to reuse the same
1241
        tests for proxy and no-proxy accesses which have
1242
        different ways of setting self.server.
1243
        """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1244
        self.build_tree_contents([('a', 'contents of a\n'),
1245
                                  ('b', 'contents of b\n'),])
2363.4.10 by Vincent Ladeuil
Complete tests.
1246
1247
    def get_user_url(self, user=None, password=None):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1248
        """Build an url embedding user and password"""
1249
        url = '%s://' % self.server._url_protocol
1250
        if user is not None:
1251
            url += user
1252
            if password is not None:
1253
                url += ':' + password
1254
            url += '@'
1255
        url += '%s:%s/' % (self.server.host, self.server.port)
1256
        return url
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1257
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1258
    def test_no_user(self):
1259
        self.server.add_user('joe', 'foo')
1260
        t = self.get_user_transport()
1261
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
1262
        # Only one 'Authentication Required' error should occur
1263
        self.assertEqual(1, self.server.auth_required_errors)
1264
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1265
    def test_empty_pass(self):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1266
        self.server.add_user('joe', '')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1267
        t = self.get_user_transport('joe', '')
2363.4.10 by Vincent Ladeuil
Complete tests.
1268
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1269
        # Only one 'Authentication Required' error should occur
1270
        self.assertEqual(1, self.server.auth_required_errors)
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1271
1272
    def test_user_pass(self):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1273
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1274
        t = self.get_user_transport('joe', 'foo')
2363.4.10 by Vincent Ladeuil
Complete tests.
1275
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1276
        # Only one 'Authentication Required' error should occur
1277
        self.assertEqual(1, self.server.auth_required_errors)
2363.4.10 by Vincent Ladeuil
Complete tests.
1278
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1279
    def test_unknown_user(self):
1280
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1281
        t = self.get_user_transport('bill', 'foo')
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1282
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1283
        # Two 'Authentication Required' errors should occur (the
1284
        # initial 'who are you' and 'I don't know you, who are
1285
        # you').
1286
        self.assertEqual(2, self.server.auth_required_errors)
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1287
2363.4.10 by Vincent Ladeuil
Complete tests.
1288
    def test_wrong_pass(self):
1289
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1290
        t = self.get_user_transport('joe', 'bar')
2363.4.10 by Vincent Ladeuil
Complete tests.
1291
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1292
        # Two 'Authentication Required' errors should occur (the
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1293
        # initial 'who are you' and 'this is not you, who are you')
1294
        self.assertEqual(2, self.server.auth_required_errors)
2363.4.10 by Vincent Ladeuil
Complete tests.
1295
1296
    def test_prompt_for_password(self):
1297
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1298
        t = self.get_user_transport('joe', None)
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
1299
        stdout = tests.StringIOWrapper()
1300
        ui.ui_factory = tests.TestUIFactory(stdin='foo\n', stdout=stdout)
2363.4.10 by Vincent Ladeuil
Complete tests.
1301
        self.assertEqual('contents of a\n',t.get('a').read())
1302
        # stdin should be empty
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1303
        self.assertEqual('', ui.ui_factory.stdin.readline())
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1304
        self._check_password_prompt(t._unqualified_scheme, 'joe',
1305
                                    stdout.getvalue())
2363.4.10 by Vincent Ladeuil
Complete tests.
1306
        # And we shouldn't prompt again for a different request
1307
        # against the same transport.
1308
        self.assertEqual('contents of b\n',t.get('b').read())
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1309
        t2 = t.clone()
1310
        # And neither against a clone
1311
        self.assertEqual('contents of b\n',t2.get('b').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1312
        # Only one 'Authentication Required' error should occur
1313
        self.assertEqual(1, self.server.auth_required_errors)
1314
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1315
    def _check_password_prompt(self, scheme, user, actual_prompt):
1316
        expected_prompt = (self._password_prompt_prefix
1317
                           + ("%s %s@%s:%d, Realm: '%s' password: "
1318
                              % (scheme.upper(),
1319
                                 user, self.server.host, self.server.port,
1320
                                 self.server.auth_realm)))
1321
        self.assertEquals(expected_prompt, actual_prompt)
1322
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1323
    def test_no_prompt_for_password_when_using_auth_config(self):
1324
        user =' joe'
1325
        password = 'foo'
1326
        stdin_content = 'bar\n'  # Not the right password
1327
        self.server.add_user(user, password)
1328
        t = self.get_user_transport(user, None)
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
1329
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
1330
                                            stdout=tests.StringIOWrapper())
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1331
        # Create a minimal config file with the right password
1332
        conf = config.AuthenticationConfig()
1333
        conf._get_config().update(
1334
            {'httptest': {'scheme': 'http', 'port': self.server.port,
1335
                          'user': user, 'password': password}})
1336
        conf._save()
1337
        # Issue a request to the server to connect
1338
        self.assertEqual('contents of a\n',t.get('a').read())
1339
        # stdin should have  been left untouched
1340
        self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
1341
        # Only one 'Authentication Required' error should occur
1342
        self.assertEqual(1, self.server.auth_required_errors)
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1343
1344
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1345
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1346
class TestHTTPAuth(TestAuth):
1347
    """Test HTTP authentication schemes.
1348
1349
    Daughter classes MUST inherit from TestCaseWithWebserver too.
1350
    """
1351
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1352
    _auth_header = 'Authorization'
1353
1354
    def setUp(self):
1355
        TestCaseWithWebserver.setUp(self)
1356
        self.server = self.get_readonly_server()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1357
        TestAuth.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1358
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1359
    def get_user_transport(self, user=None, password=None):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1360
        return self._transport(self.get_user_url(user, password))
1361
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1362
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1363
class TestProxyAuth(TestAuth):
1364
    """Test proxy authentication schemes.
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1365
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1366
    Daughter classes MUST also inherit from TestCaseWithWebserver.
1367
    """
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1368
    _auth_header = 'Proxy-authorization'
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1369
    _password_prompt_prefix = 'Proxy '
1370
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1371
1372
    def setUp(self):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1373
        TestCaseWithWebserver.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1374
        self.server = self.get_readonly_server()
1375
        self._old_env = {}
1376
        self.addCleanup(self._restore_env)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1377
        TestAuth.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1378
        # Override the contents to avoid false positives
1379
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
1380
                                  ('b', 'not proxied contents of b\n'),
1381
                                  ('a-proxied', 'contents of a\n'),
1382
                                  ('b-proxied', 'contents of b\n'),
1383
                                  ])
1384
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1385
    def get_user_transport(self, user=None, password=None):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1386
        self._install_env({'all_proxy': self.get_user_url(user, password)})
1387
        return self._transport(self.server.get_url())
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1388
1389
    def _install_env(self, env):
1390
        for name, value in env.iteritems():
1391
            self._old_env[name] = osutils.set_or_unset_env(name, value)
1392
1393
    def _restore_env(self):
1394
        for name, value in self._old_env.iteritems():
1395
            osutils.set_or_unset_env(name, value)
1396
1397
1398
class TestHTTPBasicAuth(TestHTTPAuth, TestCaseWithWebserver):
1399
    """Test http basic authentication scheme"""
1400
1401
    _transport = HttpTransport_urllib
1402
1403
    def create_transport_readonly_server(self):
1404
        return HTTPBasicAuthServer()
1405
1406
1407
class TestHTTPProxyBasicAuth(TestProxyAuth, TestCaseWithWebserver):
1408
    """Test proxy basic authentication scheme"""
1409
1410
    _transport = HttpTransport_urllib
1411
1412
    def create_transport_readonly_server(self):
1413
        return ProxyBasicAuthServer()
1414
1415
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1416
class TestDigestAuth(object):
1417
    """Digest Authentication specific tests"""
1418
1419
    def test_changing_nonce(self):
1420
        self.server.add_user('joe', 'foo')
1421
        t = self.get_user_transport('joe', 'foo')
1422
        self.assertEqual('contents of a\n', t.get('a').read())
1423
        self.assertEqual('contents of b\n', t.get('b').read())
1424
        # Only one 'Authentication Required' error should have
1425
        # occured so far
1426
        self.assertEqual(1, self.server.auth_required_errors)
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1427
        # The server invalidates the current nonce
1428
        self.server.auth_nonce = self.server.auth_nonce + '. No, now!'
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1429
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1430
        # Two 'Authentication Required' errors should occur (the
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1431
        # initial 'who are you' and a second 'who are you' with the new nonce)
1432
        self.assertEqual(2, self.server.auth_required_errors)
1433
1434
1435
class TestHTTPDigestAuth(TestHTTPAuth, TestDigestAuth, TestCaseWithWebserver):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1436
    """Test http digest authentication scheme"""
1437
1438
    _transport = HttpTransport_urllib
1439
1440
    def create_transport_readonly_server(self):
1441
        return HTTPDigestAuthServer()
1442
1443
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1444
class TestHTTPProxyDigestAuth(TestProxyAuth, TestDigestAuth,
1445
                              TestCaseWithWebserver):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1446
    """Test proxy digest authentication scheme"""
1447
1448
    _transport = HttpTransport_urllib
1449
1450
    def create_transport_readonly_server(self):
1451
        return ProxyDigestAuthServer()
1452