/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart_transport.py

Merge up with bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
        server,
40
40
        vfs,
41
41
)
42
 
from bzrlib.tests.HTTPTestUtil import (
 
42
from bzrlib.tests.http_utils import (
43
43
        HTTPServerWithSmarts,
44
44
        SmartRequestHandler,
45
45
        )
80
80
        return self.vendor.read_from, self.vendor.write_to
81
81
 
82
82
 
 
83
class _InvalidHostnameFeature(tests.Feature):
 
84
    """Does 'non_existent.invalid' fail to resolve?
 
85
    
 
86
    RFC 2606 states that .invalid is reserved for invalid domain names, and
 
87
    also underscores are not a valid character in domain names.  Despite this,
 
88
    it's possible a badly misconfigured name server might decide to always
 
89
    return an address for any name, so this feature allows us to distinguish a
 
90
    broken system from a broken test.
 
91
    """
 
92
 
 
93
    def _probe(self):
 
94
        try:
 
95
            socket.gethostbyname('non_existent.invalid')
 
96
        except socket.gaierror:
 
97
            # The host name failed to resolve.  Good.
 
98
            return True
 
99
        else:
 
100
            return False
 
101
 
 
102
    def feature_name(self):
 
103
        return 'invalid hostname'
 
104
 
 
105
InvalidHostnameFeature = _InvalidHostnameFeature()
 
106
 
83
107
 
84
108
class SmartClientMediumTests(tests.TestCase):
85
109
    """Tests for SmartClientMedium.
443
467
        # really did disconnect.
444
468
        medium.disconnect()
445
469
 
 
470
    def test_tcp_client_host_unknown_connection_error(self):
 
471
        self.requireFeature(InvalidHostnameFeature)
 
472
        client_medium = medium.SmartTCPClientMedium(
 
473
            'non_existent.invalid', 4155)
 
474
        self.assertRaises(
 
475
            errors.ConnectionError, client_medium._ensure_connection)
 
476
 
446
477
 
447
478
class TestSmartClientStreamMediumRequest(tests.TestCase):
448
479
    """Tests the for SmartClientStreamMediumRequest.
1389
1420
        self.assertContainsRe(test_log, 'Traceback')
1390
1421
        self.assertContainsRe(test_log, 'SmartProtocolError')
1391
1422
 
 
1423
    def test_connection_closed_reporting(self):
 
1424
        input = StringIO()
 
1425
        output = StringIO()
 
1426
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
 
1427
        request = client_medium.get_request()
 
1428
        smart_protocol = self.client_protocol_class(request)
 
1429
        smart_protocol.call('hello')
 
1430
        ex = self.assertRaises(errors.ConnectionReset, 
 
1431
            smart_protocol.read_response_tuple)
 
1432
        self.assertEqual("Connection closed: "
 
1433
            "please check connectivity and permissions "
 
1434
            "(and try -Dhpss if further diagnosis is required)", str(ex))
 
1435
 
1392
1436
 
1393
1437
class TestSmartProtocolOne(TestSmartProtocol, CommonSmartProtocolTestMixin):
1394
1438
    """Tests for the smart protocol version one."""
1424
1468
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1425
1469
            '1,2\n3,4\n100,200', self.client_protocol)
1426
1470
 
1427
 
    def test_connection_closed_reporting(self):
1428
 
        input = StringIO()
1429
 
        output = StringIO()
1430
 
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1431
 
        request = client_medium.get_request()
1432
 
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1433
 
        smart_protocol.call('hello')
1434
 
        ex = self.assertRaises(errors.ConnectionReset, 
1435
 
            smart_protocol.read_response_tuple)
1436
 
        self.assertEqual("Connection closed: "
1437
 
            "please check connectivity and permissions "
1438
 
            "(and try -Dhpss if further diagnosis is required)", str(ex))
1439
 
 
1440
1471
    def test_accept_bytes_of_bad_request_to_protocol(self):
1441
1472
        out_stream = StringIO()
1442
1473
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2277
2308
            ('foo', 'bar'), 'bytes')
2278
2309
        self.assertEqual(('foo', 'bar'), response.args)
2279
2310
        self.assertEqual('bytes', response.body)
 
2311
        # repr(response) doesn't trigger exceptions.
 
2312
        repr(response)
2280
2313
 
2281
2314
    def test_construct_with_body_stream(self):
2282
2315
        bytes_iterable = ['abc']
2306
2339
        response = request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2307
2340
        self.assertEqual(('foo', 'bar'), response.args)
2308
2341
        self.assertEqual('bytes', response.body)
 
2342
        # repr(response) doesn't trigger exceptions.
 
2343
        repr(response)
2309
2344
 
2310
2345
    def test_is_successful(self):
2311
2346
        """is_successful should return False for FailedSmartServerResponse."""
2322
2357
        return None
2323
2358
 
2324
2359
 
2325
 
class HTTPTunnellingSmokeTest(tests.TestCaseWithTransport):
2326
 
    
 
2360
class HTTPTunnellingSmokeTest(tests.TestCase):
 
2361
 
2327
2362
    def setUp(self):
2328
2363
        super(HTTPTunnellingSmokeTest, self).setUp()
2329
2364
        # We use the VFS layer as part of HTTP tunnelling tests.
2330
2365
        self._captureVar('BZR_NO_SMART_VFS', None)
2331
2366
 
2332
 
    def _test_bulk_data(self, url_protocol):
2333
 
        # We should be able to send and receive bulk data in a single message.
2334
 
        # The 'readv' command in the smart protocol both sends and receives bulk
2335
 
        # data, so we use that.
2336
 
        self.build_tree(['data-file'])
2337
 
        self.transport_readonly_server = HTTPServerWithSmarts
2338
 
 
2339
 
        http_transport = self.get_readonly_transport()
2340
 
        medium = http_transport.get_smart_medium()
2341
 
        # Since we provide the medium, the url below will be mostly ignored
2342
 
        # during the test, as long as the path is '/'.
2343
 
        remote_transport = remote.RemoteTransport('bzr://fake_host/',
2344
 
                                                  medium=medium)
2345
 
        self.assertEqual(
2346
 
            [(0, "c")], list(remote_transport.readv("data-file", [(0,1)])))
2347
 
 
2348
 
    def test_bulk_data_pycurl(self):
2349
 
        try:
2350
 
            self._test_bulk_data('http+pycurl')
2351
 
        except errors.UnsupportedProtocol, e:
2352
 
            raise tests.TestSkipped(str(e))
2353
 
    
2354
 
    def test_bulk_data_urllib(self):
2355
 
        self._test_bulk_data('http+urllib')
2356
 
 
2357
2367
    def test_smart_http_medium_request_accept_bytes(self):
2358
2368
        medium = FakeHTTPMedium()
2359
2369
        request = SmartClientHTTPMediumRequest(medium)
2363
2373
        request.finished_writing()
2364
2374
        self.assertEqual('abcdef', medium.written_request)
2365
2375
 
2366
 
    def _test_http_send_smart_request(self, url_protocol):
2367
 
        http_server = HTTPServerWithSmarts()
2368
 
        http_server._url_protocol = url_protocol
2369
 
        http_server.setUp(self.get_vfs_only_server())
2370
 
        self.addCleanup(http_server.tearDown)
2371
 
 
2372
 
        post_body = 'hello\n'
2373
 
        expected_reply_body = 'ok\x012\n'
2374
 
 
2375
 
        http_transport = get_transport(http_server.get_url())
2376
 
        medium = http_transport.get_smart_medium()
2377
 
        response = medium.send_http_smart_request(post_body)
2378
 
        reply_body = response.read()
2379
 
        self.assertEqual(expected_reply_body, reply_body)
2380
 
 
2381
 
    def test_http_send_smart_request_pycurl(self):
2382
 
        try:
2383
 
            self._test_http_send_smart_request('http+pycurl')
2384
 
        except errors.UnsupportedProtocol, e:
2385
 
            raise tests.TestSkipped(str(e))
2386
 
 
2387
 
    def test_http_send_smart_request_urllib(self):
2388
 
        self._test_http_send_smart_request('http+urllib')
2389
 
 
2390
 
    def test_http_server_with_smarts(self):
2391
 
        self.transport_readonly_server = HTTPServerWithSmarts
2392
 
 
2393
 
        post_body = 'hello\n'
2394
 
        expected_reply_body = 'ok\x012\n'
2395
 
 
2396
 
        smart_server_url = self.get_readonly_url('.bzr/smart')
2397
 
        reply = urllib2.urlopen(smart_server_url, post_body).read()
2398
 
 
2399
 
        self.assertEqual(expected_reply_body, reply)
2400
 
 
2401
 
    def test_smart_http_server_post_request_handler(self):
2402
 
        self.transport_readonly_server = HTTPServerWithSmarts
2403
 
        httpd = self.get_readonly_server()._get_httpd()
2404
 
 
2405
 
        socket = SampleSocket(
2406
 
            'POST /.bzr/smart HTTP/1.0\r\n'
2407
 
            # HTTP/1.0 posts must have a Content-Length.
2408
 
            'Content-Length: 6\r\n'
2409
 
            '\r\n'
2410
 
            'hello\n')
2411
 
        # Beware: the ('localhost', 80) below is the
2412
 
        # client_address parameter, but we don't have one because
2413
 
        # we have defined a socket which is not bound to an
2414
 
        # address. The test framework never uses this client
2415
 
        # address, so far...
2416
 
        request_handler = SmartRequestHandler(socket, ('localhost', 80), httpd)
2417
 
        response = socket.writefile.getvalue()
2418
 
        self.assertStartsWith(response, 'HTTP/1.0 200 ')
2419
 
        # This includes the end of the HTTP headers, and all the body.
2420
 
        expected_end_of_response = '\r\n\r\nok\x012\n'
2421
 
        self.assertEndsWith(response, expected_end_of_response)
2422
 
 
2423
 
 
2424
 
class SampleSocket(object):
2425
 
    """A socket-like object for use in testing the HTTP request handler."""
2426
 
    
2427
 
    def __init__(self, socket_read_content):
2428
 
        """Constructs a sample socket.
2429
 
 
2430
 
        :param socket_read_content: a byte sequence
2431
 
        """
2432
 
        # Use plain python StringIO so we can monkey-patch the close method to
2433
 
        # not discard the contents.
2434
 
        from StringIO import StringIO
2435
 
        self.readfile = StringIO(socket_read_content)
2436
 
        self.writefile = StringIO()
2437
 
        self.writefile.close = lambda: None
2438
 
        
2439
 
    def makefile(self, mode='r', bufsize=None):
2440
 
        if 'r' in mode:
2441
 
            return self.readfile
2442
 
        else:
2443
 
            return self.writefile
2444
 
 
2445
2376
 
2446
2377
class RemoteHTTPTransportTestCase(tests.TestCase):
2447
2378
 
2458
2389
                         new_transport._http_transport)
2459
2390
        self.assertEqual('child_dir/foo', new_transport._remote_path('foo'))
2460
2391
 
2461
 
    def test_remote_path_after_clone_parent(self):
2462
 
        # However, accessing a parent directory should go direct to the parent's
2463
 
        # URL.  We don't send relpaths like "../foo" in smart requests.
2464
 
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/path1/path2')
2465
 
        new_transport = base_transport.clone('..')
2466
 
        self.assertEqual('foo', new_transport._remote_path('foo'))
2467
 
        new_transport = base_transport.clone('../')
2468
 
        self.assertEqual('foo', new_transport._remote_path('foo'))
2469
 
        new_transport = base_transport.clone('../abc')
2470
 
        self.assertEqual('foo', new_transport._remote_path('foo'))
2471
 
        # "abc/../.." should be equivalent to ".."
2472
 
        new_transport = base_transport.clone('abc/../..')
2473
 
        self.assertEqual('foo', new_transport._remote_path('foo'))
2474
 
 
2475
2392
    def test_remote_path_unnormal_base(self):
2476
2393
        # If the transport's base isn't normalised, the _remote_path should
2477
2394
        # still be calculated correctly.