~bzr-pqm/bzr/bzr.dev

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