~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
test HttpTransport._post.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
21
21
 
 
22
import errno
 
23
import select
22
24
import socket
 
25
import threading
23
26
 
24
27
import bzrlib
25
 
from bzrlib.errors import DependencyNotPresent
 
28
from bzrlib.errors import DependencyNotPresent, UnsupportedProtocol
26
29
from bzrlib.tests import TestCase, TestSkipped
27
 
from bzrlib.transport import Transport
 
30
from bzrlib.transport import get_transport, Transport
28
31
from bzrlib.transport.http import extract_auth, HttpTransportBase
29
32
from bzrlib.transport.http._urllib import HttpTransport_urllib
30
33
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
31
34
 
32
35
 
33
 
class FakeManager (object):
 
36
class FakeManager(object):
34
37
 
35
38
    def __init__(self):
36
39
        self.credentials = []
39
42
        self.credentials.append([realm, host, username, password])
40
43
 
41
44
 
 
45
class RecordingServer(object):
 
46
    """A fake HTTP server.
 
47
    
 
48
    It records the bytes sent to it, and replies with a 200.
 
49
    """
 
50
 
 
51
    def __init__(self, expect_body_tail=None):
 
52
        self._expect_body_tail = expect_body_tail
 
53
        self.host = None
 
54
        self.port = None
 
55
        self.received_bytes = ''
 
56
 
 
57
    def setUp(self):
 
58
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
59
        self._sock.bind(('127.0.0.1', 0))
 
60
        self.host, self.port = self._sock.getsockname()
 
61
        self._ready = threading.Event()
 
62
        self._thread = threading.Thread(target=self._accept_read_and_reply)
 
63
        self._thread.setDaemon(True)
 
64
        self._thread.start()
 
65
        self._ready.wait(5)
 
66
 
 
67
    def _accept_read_and_reply(self):
 
68
        self._sock.listen(1)
 
69
        self._ready.set()
 
70
        self._sock.settimeout(5)
 
71
        try:
 
72
            conn, address = self._sock.accept()
 
73
            # On win32, the accepted connection will be non-blocking to start
 
74
            # with because we're using settimeout.
 
75
            conn.setblocking(True)
 
76
            while not self.received_bytes.endswith(self._expect_body_tail):
 
77
                self.received_bytes += conn.recv(4096)
 
78
            conn.sendall('HTTP/1.1 200 OK\r\n')
 
79
        except socket.timeout:
 
80
            # Make sure the client isn't stuck waiting for us to e.g. accept.
 
81
            self._sock.close()
 
82
 
 
83
    def tearDown(self):
 
84
        try:
 
85
            self._sock.close()
 
86
        except socket.error:
 
87
            # We might have already closed it.  We don't care.
 
88
            pass
 
89
        self.host = None
 
90
        self.port = None
 
91
 
 
92
 
42
93
class TestHttpUrls(TestCase):
43
94
 
44
95
    def test_url_parsing(self):
167
218
        self._prep_tree()
168
219
 
169
220
 
170
 
 
171
221
class TestHttpTransportRegistration(TestCase):
172
222
    """Test registrations of various http implementations"""
173
223
 
204
254
        self.assertEqual([[10, 12], [22, 26]], ranges)
205
255
 
206
256
 
 
257
class TestPost(TestCase):
 
258
 
 
259
    def _test_post_body_is_received(self, scheme):
 
260
        server = RecordingServer(expect_body_tail='end-of-body')
 
261
        server.setUp()
 
262
        self.addCleanup(server.tearDown)
 
263
        url = '%s://%s:%s/' % (scheme, server.host, server.port)
 
264
        try:
 
265
            http_transport = get_transport(url)
 
266
        except UnsupportedProtocol:
 
267
            raise TestSkipped('%s not available' % scheme)
 
268
        code, response = http_transport._post('abc def end-of-body')
 
269
        self.assertTrue(
 
270
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
 
271
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
 
272
        # The transport should not be assuming that the server can accept
 
273
        # chunked encoding the first time it connects, because HTTP/1.1, so we
 
274
        # check for the literal string.
 
275
        self.assertTrue(
 
276
            server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
 
277
 
 
278
    def test_post_body_is_received_urllib(self):
 
279
        self._test_post_body_is_received('http+urllib')
 
280
 
 
281
    def test_post_body_is_received_pycurl(self):
 
282
        self._test_post_body_is_received('http+pycurl')
 
283
 
 
284
 
207
285
class TestRangeHeader(TestCase):
208
286
    """Test range_header method"""
209
287
 
227
305
        self.check_header('0-9,300-5000,-50',
228
306
                          ranges=[(0,9), (300,5000)],
229
307
                          tail=50)
 
308
 
 
309
        
 
310
class TestRecordingServer(TestCase):
 
311
 
 
312
    def test_create(self):
 
313
        server = RecordingServer(expect_body_tail=None)
 
314
        self.assertEqual('', server.received_bytes)
 
315
        self.assertEqual(None, server.host)
 
316
        self.assertEqual(None, server.port)
 
317
 
 
318
    def test_setUp_and_tearDown(self):
 
319
        server = RecordingServer(expect_body_tail=None)
 
320
        server.setUp()
 
321
        try:
 
322
            self.assertNotEqual(None, server.host)
 
323
            self.assertNotEqual(None, server.port)
 
324
        finally:
 
325
            server.tearDown()
 
326
        self.assertEqual(None, server.host)
 
327
        self.assertEqual(None, server.port)
 
328
 
 
329
    def test_send_receive_bytes(self):
 
330
        server = RecordingServer(expect_body_tail='c')
 
331
        server.setUp()
 
332
        self.addCleanup(server.tearDown)
 
333
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
334
        sock.connect((server.host, server.port))
 
335
        sock.sendall('abc')
 
336
        self.assertEqual('HTTP/1.1 200 OK\r\n',
 
337
                         sock.recv(4096, socket.MSG_WAITALL))
 
338
        self.assertEqual('abc', server.received_bytes)