80
80
return self.vendor.read_from, self.vendor.write_to
83
class _InvalidHostnameFeature(tests.Feature):
84
"""Does 'non_existent.invalid' fail to resolve?
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.
95
socket.gethostbyname('non_existent.invalid')
96
except socket.gaierror:
97
# The host name failed to resolve. Good.
102
def feature_name(self):
103
return 'invalid hostname'
105
InvalidHostnameFeature = _InvalidHostnameFeature()
84
108
class SmartClientMediumTests(tests.TestCase):
85
109
"""Tests for SmartClientMedium.
1389
1420
self.assertContainsRe(test_log, 'Traceback')
1390
1421
self.assertContainsRe(test_log, 'SmartProtocolError')
1423
def test_connection_closed_reporting(self):
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))
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)
1427
def test_connection_closed_reporting(self):
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))
1440
1471
def test_accept_bytes_of_bad_request_to_protocol(self):
1441
1472
out_stream = StringIO()
1442
1473
smart_protocol = protocol.SmartServerRequestProtocolOne(
2325
class HTTPTunnellingSmokeTest(tests.TestCaseWithTransport):
2360
class HTTPTunnellingSmokeTest(tests.TestCase):
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)
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
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/',
2346
[(0, "c")], list(remote_transport.readv("data-file", [(0,1)])))
2348
def test_bulk_data_pycurl(self):
2350
self._test_bulk_data('http+pycurl')
2351
except errors.UnsupportedProtocol, e:
2352
raise tests.TestSkipped(str(e))
2354
def test_bulk_data_urllib(self):
2355
self._test_bulk_data('http+urllib')
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)
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)
2372
post_body = 'hello\n'
2373
expected_reply_body = 'ok\x012\n'
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)
2381
def test_http_send_smart_request_pycurl(self):
2383
self._test_http_send_smart_request('http+pycurl')
2384
except errors.UnsupportedProtocol, e:
2385
raise tests.TestSkipped(str(e))
2387
def test_http_send_smart_request_urllib(self):
2388
self._test_http_send_smart_request('http+urllib')
2390
def test_http_server_with_smarts(self):
2391
self.transport_readonly_server = HTTPServerWithSmarts
2393
post_body = 'hello\n'
2394
expected_reply_body = 'ok\x012\n'
2396
smart_server_url = self.get_readonly_url('.bzr/smart')
2397
reply = urllib2.urlopen(smart_server_url, post_body).read()
2399
self.assertEqual(expected_reply_body, reply)
2401
def test_smart_http_server_post_request_handler(self):
2402
self.transport_readonly_server = HTTPServerWithSmarts
2403
httpd = self.get_readonly_server()._get_httpd()
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'
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)
2424
class SampleSocket(object):
2425
"""A socket-like object for use in testing the HTTP request handler."""
2427
def __init__(self, socket_read_content):
2428
"""Constructs a sample socket.
2430
:param socket_read_content: a byte sequence
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
2439
def makefile(self, mode='r', bufsize=None):
2441
return self.readfile
2443
return self.writefile
2446
2377
class RemoteHTTPTransportTestCase(tests.TestCase):
2458
2389
new_transport._http_transport)
2459
2390
self.assertEqual('child_dir/foo', new_transport._remote_path('foo'))
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'))
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.