1451
1521
errors.ReadingCompleted, smart_protocol.read_body_bytes)
1524
class TestSmartProtocolTwo(TestSmartProtocol):
1525
"""Tests for the smart protocol version two.
1527
This test case is mostly the same as TestSmartProtocolOne.
1530
client_protocol_class = protocol.SmartClientRequestProtocolTwo
1531
server_protocol_class = protocol.SmartServerRequestProtocolTwo
1533
def test_construct_version_two_server_protocol(self):
1534
smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
1535
self.assertEqual('', smart_protocol.excess_buffer)
1536
self.assertEqual('', smart_protocol.in_buffer)
1537
self.assertFalse(smart_protocol.has_dispatched)
1538
self.assertEqual(1, smart_protocol.next_read_size())
1540
def test_construct_version_two_client_protocol(self):
1541
# we can construct a client protocol from a client medium request
1543
client_medium = medium.SmartSimplePipesClientMedium(None, output)
1544
request = client_medium.get_request()
1545
client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1547
def test_server_offset_serialisation(self):
1548
"""The Smart protocol serialises offsets as a comma and \n string.
1550
We check a number of boundary cases are as expected: empty, one offset,
1551
one with the order of reads not increasing (an out of order read), and
1552
one that should coalesce.
1554
self.assertOffsetSerialisation([], '', self.client_protocol)
1555
self.assertOffsetSerialisation([(1,2)], '1,2', self.client_protocol)
1556
self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
1557
self.client_protocol)
1558
self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1559
'1,2\n3,4\n100,200', self.client_protocol)
1561
def test_accept_bytes_of_bad_request_to_protocol(self):
1562
out_stream = StringIO()
1563
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1564
None, out_stream.write)
1565
smart_protocol.accept_bytes('abc')
1566
self.assertEqual('abc', smart_protocol.in_buffer)
1567
smart_protocol.accept_bytes('\n')
1569
protocol.RESPONSE_VERSION_TWO +
1570
"failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
1571
out_stream.getvalue())
1572
self.assertTrue(smart_protocol.has_dispatched)
1573
self.assertEqual(0, smart_protocol.next_read_size())
1575
def test_accept_body_bytes_to_protocol(self):
1576
protocol = self.build_protocol_waiting_for_body()
1577
self.assertEqual(6, protocol.next_read_size())
1578
protocol.accept_bytes('7\nabc')
1579
self.assertEqual(9, protocol.next_read_size())
1580
protocol.accept_bytes('defgd')
1581
protocol.accept_bytes('one\n')
1582
self.assertEqual(0, protocol.next_read_size())
1583
self.assertTrue(self.end_received)
1585
def test_accept_request_and_body_all_at_once(self):
1586
self._captureVar('BZR_NO_SMART_VFS', None)
1587
mem_transport = memory.MemoryTransport()
1588
mem_transport.put_bytes('foo', 'abcdefghij')
1589
out_stream = StringIO()
1590
smart_protocol = protocol.SmartServerRequestProtocolTwo(mem_transport,
1592
smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1593
self.assertEqual(0, smart_protocol.next_read_size())
1594
self.assertEqual(protocol.RESPONSE_VERSION_TWO +
1595
'success\nreadv\n3\ndefdone\n',
1596
out_stream.getvalue())
1597
self.assertEqual('', smart_protocol.excess_buffer)
1598
self.assertEqual('', smart_protocol.in_buffer)
1600
def test_accept_excess_bytes_are_preserved(self):
1601
out_stream = StringIO()
1602
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1603
None, out_stream.write)
1604
smart_protocol.accept_bytes('hello\nhello\n')
1605
self.assertEqual(protocol.RESPONSE_VERSION_TWO + "success\nok\x012\n",
1606
out_stream.getvalue())
1607
self.assertEqual("hello\n", smart_protocol.excess_buffer)
1608
self.assertEqual("", smart_protocol.in_buffer)
1610
def test_accept_excess_bytes_after_body(self):
1611
# The excess bytes look like the start of another request.
1612
server_protocol = self.build_protocol_waiting_for_body()
1613
server_protocol.accept_bytes(
1614
'7\nabcdefgdone\n' + protocol.RESPONSE_VERSION_TWO)
1615
self.assertTrue(self.end_received)
1616
self.assertEqual(protocol.RESPONSE_VERSION_TWO,
1617
server_protocol.excess_buffer)
1618
self.assertEqual("", server_protocol.in_buffer)
1619
server_protocol.accept_bytes('Y')
1620
self.assertEqual(protocol.RESPONSE_VERSION_TWO + "Y",
1621
server_protocol.excess_buffer)
1622
self.assertEqual("", server_protocol.in_buffer)
1624
def test_accept_excess_bytes_after_dispatch(self):
1625
out_stream = StringIO()
1626
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1627
None, out_stream.write)
1628
smart_protocol.accept_bytes('hello\n')
1629
self.assertEqual(protocol.RESPONSE_VERSION_TWO + "success\nok\x012\n",
1630
out_stream.getvalue())
1631
smart_protocol.accept_bytes(protocol.REQUEST_VERSION_TWO + 'hel')
1632
self.assertEqual(protocol.REQUEST_VERSION_TWO + "hel",
1633
smart_protocol.excess_buffer)
1634
smart_protocol.accept_bytes('lo\n')
1635
self.assertEqual(protocol.REQUEST_VERSION_TWO + "hello\n",
1636
smart_protocol.excess_buffer)
1637
self.assertEqual("", smart_protocol.in_buffer)
1639
def test__send_response_sets_finished_reading(self):
1640
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1641
None, lambda x: None)
1642
self.assertEqual(1, smart_protocol.next_read_size())
1643
smart_protocol._send_response(
1644
request.SuccessfulSmartServerResponse(('x',)))
1645
self.assertEqual(0, smart_protocol.next_read_size())
1647
def test__send_response_errors_with_base_response(self):
1648
"""Ensure that only the Successful/Failed subclasses are used."""
1649
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1650
None, lambda x: None)
1651
self.assertRaises(AttributeError, smart_protocol._send_response,
1652
request.SmartServerResponse(('x',)))
1654
def test__send_response_includes_failure_marker(self):
1655
"""FailedSmartServerResponse have 'failed\n' after the version."""
1656
out_stream = StringIO()
1657
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1658
None, out_stream.write)
1659
smart_protocol._send_response(
1660
request.FailedSmartServerResponse(('x',)))
1661
self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
1662
out_stream.getvalue())
1664
def test__send_response_includes_success_marker(self):
1665
"""SuccessfulSmartServerResponse have 'success\n' after the version."""
1666
out_stream = StringIO()
1667
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1668
None, out_stream.write)
1669
smart_protocol._send_response(
1670
request.SuccessfulSmartServerResponse(('x',)))
1671
self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
1672
out_stream.getvalue())
1674
def test_query_version(self):
1675
"""query_version on a SmartClientProtocolTwo should return a number.
1677
The protocol provides the query_version because the domain level clients
1678
may all need to be able to probe for capabilities.
1680
# What we really want to test here is that SmartClientProtocolTwo calls
1681
# accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1682
# response of tuple-encoded (ok, 1). Also, seperately we should test
1683
# the error if the response is a non-understood version.
1684
input = StringIO(protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
1686
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1687
request = client_medium.get_request()
1688
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1689
self.assertEqual(2, smart_protocol.query_version())
1691
def test_client_call_empty_response(self):
1692
# protocol.call() can get back an empty tuple as a response. This occurs
1693
# when the parsed line is an empty line, and results in a tuple with
1694
# one element - an empty string.
1695
self.assertServerToClientEncoding(
1696
protocol.RESPONSE_VERSION_TWO + 'success\n\n', ('', ), [(), ('', )])
1698
def test_client_call_three_element_response(self):
1699
# protocol.call() can get back tuples of other lengths. A three element
1700
# tuple should be unpacked as three strings.
1701
self.assertServerToClientEncoding(
1702
protocol.RESPONSE_VERSION_TWO + 'success\na\x01b\x0134\n',
1706
def test_client_call_with_body_bytes_uploads(self):
1707
# protocol.call_with_body_bytes should length-prefix the bytes onto the
1709
expected_bytes = protocol.REQUEST_VERSION_TWO + "foo\n7\nabcdefgdone\n"
1710
input = StringIO("\n")
1712
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1713
request = client_medium.get_request()
1714
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1715
smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1716
self.assertEqual(expected_bytes, output.getvalue())
1718
def test_client_call_with_body_readv_array(self):
1719
# protocol.call_with_upload should encode the readv array and then
1720
# length-prefix the bytes onto the wire.
1721
expected_bytes = protocol.REQUEST_VERSION_TWO+"foo\n7\n1,2\n5,6done\n"
1722
input = StringIO("\n")
1724
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1725
request = client_medium.get_request()
1726
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1727
smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1728
self.assertEqual(expected_bytes, output.getvalue())
1730
def test_client_read_response_tuple_sets_response_status(self):
1731
server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
1732
input = StringIO(server_bytes)
1734
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1735
request = client_medium.get_request()
1736
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1737
smart_protocol.call('foo')
1738
smart_protocol.read_response_tuple(False)
1739
self.assertEqual(True, smart_protocol.response_status)
1741
def test_client_read_body_bytes_all(self):
1742
# read_body_bytes should decode the body bytes from the wire into
1744
expected_bytes = "1234567"
1745
server_bytes = (protocol.RESPONSE_VERSION_TWO +
1746
"success\nok\n7\n1234567done\n")
1747
input = StringIO(server_bytes)
1749
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1750
request = client_medium.get_request()
1751
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1752
smart_protocol.call('foo')
1753
smart_protocol.read_response_tuple(True)
1754
self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
1756
def test_client_read_body_bytes_incremental(self):
1757
# test reading a few bytes at a time from the body
1758
# XXX: possibly we should test dribbling the bytes into the stringio
1759
# to make the state machine work harder: however, as we use the
1760
# LengthPrefixedBodyDecoder that is already well tested - we can skip
1762
expected_bytes = "1234567"
1763
server_bytes = (protocol.RESPONSE_VERSION_TWO +
1764
"success\nok\n7\n1234567done\n")
1765
input = StringIO(server_bytes)
1767
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1768
request = client_medium.get_request()
1769
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1770
smart_protocol.call('foo')
1771
smart_protocol.read_response_tuple(True)
1772
self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1773
self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1774
self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1775
self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
1777
def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1778
# cancelling the expected body needs to finish the request, but not
1779
# read any more bytes.
1780
expected_bytes = "1234567"
1781
server_bytes = (protocol.RESPONSE_VERSION_TWO +
1782
"success\nok\n7\n1234567done\n")
1783
input = StringIO(server_bytes)
1785
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1786
request = client_medium.get_request()
1787
smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1788
smart_protocol.call('foo')
1789
smart_protocol.read_response_tuple(True)
1790
smart_protocol.cancel_read_body()
1791
self.assertEqual(len(protocol.RESPONSE_VERSION_TWO + 'success\nok\n'),
1794
errors.ReadingCompleted, smart_protocol.read_body_bytes)
1797
class TestSmartClientUnicode(tests.TestCase):
1798
"""_SmartClient tests for unicode arguments.
1800
Unicode arguments to call_with_body_bytes are not correct (remote method
1801
names, arguments, and bodies must all be expressed as byte strings), but
1802
_SmartClient should gracefully reject them, rather than getting into a
1803
broken state that prevents future correct calls from working. That is, it
1804
should be possible to issue more requests on the medium afterwards, rather
1805
than allowing one bad call to call_with_body_bytes to cause later calls to
1806
mysteriously fail with TooManyConcurrentRequests.
1809
def assertCallDoesNotBreakMedium(self, method, args, body):
1810
"""Call a medium with the given method, args and body, then assert that
1811
the medium is left in a sane state, i.e. is capable of allowing further
1814
input = StringIO("\n")
1816
client_medium = medium.SmartSimplePipesClientMedium(input, output)
1817
smart_client = client._SmartClient(client_medium)
1818
self.assertRaises(TypeError,
1819
smart_client.call_with_body_bytes, method, args, body)
1820
self.assertEqual("", output.getvalue())
1821
self.assertEqual(None, client_medium._current_request)
1823
def test_call_with_body_bytes_unicode_method(self):
1824
self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
1826
def test_call_with_body_bytes_unicode_args(self):
1827
self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
1828
self.assertCallDoesNotBreakMedium('method', ('arg1', u'arg2'), 'body')
1830
def test_call_with_body_bytes_unicode_body(self):
1831
self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
1454
1834
class LengthPrefixedBodyDecoder(tests.TestCase):
1456
1836
# XXX: TODO: make accept_reading_trailer invoke translate_response or