~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart_transport.py

  • Committer: Alexander Belchenko
  • Date: 2007-11-19 22:54:30 UTC
  • mfrom: (3006 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3008.
  • Revision ID: bialix@ukr.net-20071119225430-x0ewosrsagis0yno
merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1661
1661
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1662
1662
            '1,2\n3,4\n100,200', self.client_protocol)
1663
1663
 
 
1664
    def assertBodyStreamSerialisation(self, expected_serialisation,
 
1665
                                      body_stream):
 
1666
        """Assert that body_stream is serialised as expected_serialisation."""
 
1667
        out_stream = StringIO()
 
1668
        protocol._send_stream(body_stream, out_stream.write)
 
1669
        self.assertEqual(expected_serialisation, out_stream.getvalue())
 
1670
 
 
1671
    def assertBodyStreamRoundTrips(self, body_stream):
 
1672
        """Assert that body_stream is the same after being serialised and
 
1673
        deserialised.
 
1674
        """
 
1675
        out_stream = StringIO()
 
1676
        protocol._send_stream(body_stream, out_stream.write)
 
1677
        decoder = protocol.ChunkedBodyDecoder()
 
1678
        decoder.accept_bytes(out_stream.getvalue())
 
1679
        decoded_stream = list(iter(decoder.read_next_chunk, None))
 
1680
        self.assertEqual(body_stream, decoded_stream)
 
1681
 
 
1682
    def test_body_stream_serialisation_empty(self):
 
1683
        """A body_stream with no bytes can be serialised."""
 
1684
        self.assertBodyStreamSerialisation('chunked\nEND\n', [])
 
1685
        self.assertBodyStreamRoundTrips([])
 
1686
 
 
1687
    def test_body_stream_serialisation(self):
 
1688
        stream = ['chunk one', 'chunk two', 'chunk three']
 
1689
        self.assertBodyStreamSerialisation(
 
1690
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
 
1691
            'END\n',
 
1692
            stream)
 
1693
        self.assertBodyStreamRoundTrips(stream)
 
1694
 
 
1695
    def test_body_stream_with_empty_element_serialisation(self):
 
1696
        """A body stream can include ''.
 
1697
 
 
1698
        The empty string can be transmitted like any other string.
 
1699
        """
 
1700
        stream = ['', 'chunk']
 
1701
        self.assertBodyStreamSerialisation(
 
1702
            'chunked\n' + '0\n' + '5\nchunk' + 'END\n', stream)
 
1703
        self.assertBodyStreamRoundTrips(stream)
 
1704
 
 
1705
    def test_body_stream_error_serialistion(self):
 
1706
        stream = ['first chunk',
 
1707
                  request.FailedSmartServerResponse(
 
1708
                      ('FailureName', 'failure arg'))]
 
1709
        expected_bytes = (
 
1710
            'chunked\n' + 'b\nfirst chunk' +
 
1711
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
 
1712
            'END\n')
 
1713
        self.assertBodyStreamSerialisation(expected_bytes, stream)
 
1714
        self.assertBodyStreamRoundTrips(stream)
 
1715
 
1664
1716
    def test_accept_bytes_of_bad_request_to_protocol(self):
1665
1717
        out_stream = StringIO()
1666
1718
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1747
1799
            request.SuccessfulSmartServerResponse(('x',)))
1748
1800
        self.assertEqual(0, smart_protocol.next_read_size())
1749
1801
 
 
1802
    def test__send_response_with_body_stream_sets_finished_reading(self):
 
1803
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
 
1804
            None, lambda x: None)
 
1805
        self.assertEqual(1, smart_protocol.next_read_size())
 
1806
        smart_protocol._send_response(
 
1807
            request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
 
1808
        self.assertEqual(0, smart_protocol.next_read_size())
 
1809
 
1750
1810
    def test__send_response_errors_with_base_response(self):
1751
1811
        """Ensure that only the Successful/Failed subclasses are used."""
1752
1812
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1880
1940
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1881
1941
        # cancelling the expected body needs to finish the request, but not
1882
1942
        # read any more bytes.
1883
 
        expected_bytes = "1234567"
1884
1943
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
1885
1944
                        "success\nok\n7\n1234567done\n")
1886
1945
        input = StringIO(server_bytes)
1896
1955
        self.assertRaises(
1897
1956
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1898
1957
 
 
1958
    def test_streamed_body_bytes(self):
 
1959
        body_header = 'chunked\n'
 
1960
        two_body_chunks = "4\n1234" + "3\n567"
 
1961
        body_terminator = "END\n"
 
1962
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
 
1963
                        "success\nok\n" + body_header + two_body_chunks +
 
1964
                        body_terminator)
 
1965
        input = StringIO(server_bytes)
 
1966
        output = StringIO()
 
1967
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
 
1968
        request = client_medium.get_request()
 
1969
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
 
1970
        smart_protocol.call('foo')
 
1971
        smart_protocol.read_response_tuple(True)
 
1972
        stream = smart_protocol.read_streamed_body()
 
1973
        self.assertEqual(['1234', '567'], list(stream))
 
1974
 
 
1975
    def test_read_streamed_body_error(self):
 
1976
        """When a stream is interrupted by an error..."""
 
1977
        body_header = 'chunked\n'
 
1978
        a_body_chunk = '4\naaaa'
 
1979
        err_signal = 'ERR\n'
 
1980
        err_chunks = 'a\nerror arg1' + '4\narg2'
 
1981
        finish = 'END\n'
 
1982
        body = body_header + a_body_chunk + err_signal + err_chunks + finish
 
1983
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
 
1984
                        "success\nok\n" + body)
 
1985
        input = StringIO(server_bytes)
 
1986
        output = StringIO()
 
1987
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
 
1988
        smart_request = client_medium.get_request()
 
1989
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
 
1990
        smart_protocol.call('foo')
 
1991
        smart_protocol.read_response_tuple(True)
 
1992
        expected_chunks = [
 
1993
            'aaaa',
 
1994
            request.FailedSmartServerResponse(('error arg1', 'arg2'))]
 
1995
        stream = smart_protocol.read_streamed_body()
 
1996
        self.assertEqual(expected_chunks, list(stream))
 
1997
 
1899
1998
 
1900
1999
class TestSmartClientUnicode(tests.TestCase):
1901
2000
    """_SmartClient tests for unicode arguments.
2001
2100
        self.assertEqual('', decoder.unused_data)
2002
2101
 
2003
2102
 
 
2103
class TestChunkedBodyDecoder(tests.TestCase):
 
2104
    """Tests for ChunkedBodyDecoder.
 
2105
    
 
2106
    This is the body decoder used for protocol version two.
 
2107
    """
 
2108
 
 
2109
    def test_construct(self):
 
2110
        decoder = protocol.ChunkedBodyDecoder()
 
2111
        self.assertFalse(decoder.finished_reading)
 
2112
        self.assertEqual(8, decoder.next_read_size())
 
2113
        self.assertEqual(None, decoder.read_next_chunk())
 
2114
        self.assertEqual('', decoder.unused_data)
 
2115
 
 
2116
    def test_empty_content(self):
 
2117
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
 
2118
        """
 
2119
        decoder = protocol.ChunkedBodyDecoder()
 
2120
        decoder.accept_bytes('chunked\n')
 
2121
        decoder.accept_bytes('END\n')
 
2122
        self.assertTrue(decoder.finished_reading)
 
2123
        self.assertEqual(None, decoder.read_next_chunk())
 
2124
        self.assertEqual('', decoder.unused_data)
 
2125
 
 
2126
    def test_one_chunk(self):
 
2127
        """A body in a single chunk is decoded correctly."""
 
2128
        decoder = protocol.ChunkedBodyDecoder()
 
2129
        decoder.accept_bytes('chunked\n')
 
2130
        chunk_length = 'f\n'
 
2131
        chunk_content = '123456789abcdef'
 
2132
        finish = 'END\n'
 
2133
        decoder.accept_bytes(chunk_length + chunk_content + finish)
 
2134
        self.assertTrue(decoder.finished_reading)
 
2135
        self.assertEqual(chunk_content, decoder.read_next_chunk())
 
2136
        self.assertEqual('', decoder.unused_data)
 
2137
        
 
2138
    def test_incomplete_chunk(self):
 
2139
        """When there are less bytes in the chunk than declared by the length,
 
2140
        then we haven't finished reading yet.
 
2141
        """
 
2142
        decoder = protocol.ChunkedBodyDecoder()
 
2143
        decoder.accept_bytes('chunked\n')
 
2144
        chunk_length = '8\n'
 
2145
        three_bytes = '123'
 
2146
        decoder.accept_bytes(chunk_length + three_bytes)
 
2147
        self.assertFalse(decoder.finished_reading)
 
2148
        self.assertEqual(
 
2149
            5 + 4, decoder.next_read_size(),
 
2150
            "The next_read_size hint should be the number of missing bytes in "
 
2151
            "this chunk plus 4 (the length of the end-of-body marker: "
 
2152
            "'END\\n')")
 
2153
        self.assertEqual(None, decoder.read_next_chunk())
 
2154
 
 
2155
    def test_incomplete_length(self):
 
2156
        """A chunk length hasn't been read until a newline byte has been read.
 
2157
        """
 
2158
        decoder = protocol.ChunkedBodyDecoder()
 
2159
        decoder.accept_bytes('chunked\n')
 
2160
        decoder.accept_bytes('9')
 
2161
        self.assertEqual(
 
2162
            1, decoder.next_read_size(),
 
2163
            "The next_read_size hint should be 1, because we don't know the "
 
2164
            "length yet.")
 
2165
        decoder.accept_bytes('\n')
 
2166
        self.assertEqual(
 
2167
            9 + 4, decoder.next_read_size(),
 
2168
            "The next_read_size hint should be the length of the chunk plus 4 "
 
2169
            "(the length of the end-of-body marker: 'END\\n')")
 
2170
        self.assertFalse(decoder.finished_reading)
 
2171
        self.assertEqual(None, decoder.read_next_chunk())
 
2172
 
 
2173
    def test_two_chunks(self):
 
2174
        """Content from multiple chunks is concatenated."""
 
2175
        decoder = protocol.ChunkedBodyDecoder()
 
2176
        decoder.accept_bytes('chunked\n')
 
2177
        chunk_one = '3\naaa'
 
2178
        chunk_two = '5\nbbbbb'
 
2179
        finish = 'END\n'
 
2180
        decoder.accept_bytes(chunk_one + chunk_two + finish)
 
2181
        self.assertTrue(decoder.finished_reading)
 
2182
        self.assertEqual('aaa', decoder.read_next_chunk())
 
2183
        self.assertEqual('bbbbb', decoder.read_next_chunk())
 
2184
        self.assertEqual(None, decoder.read_next_chunk())
 
2185
        self.assertEqual('', decoder.unused_data)
 
2186
 
 
2187
    def test_excess_bytes(self):
 
2188
        """Bytes after the chunked body are reported as unused bytes."""
 
2189
        decoder = protocol.ChunkedBodyDecoder()
 
2190
        decoder.accept_bytes('chunked\n')
 
2191
        chunked_body = "5\naaaaaEND\n"
 
2192
        excess_bytes = "excess bytes"
 
2193
        decoder.accept_bytes(chunked_body + excess_bytes)
 
2194
        self.assertTrue(decoder.finished_reading)
 
2195
        self.assertEqual('aaaaa', decoder.read_next_chunk())
 
2196
        self.assertEqual(excess_bytes, decoder.unused_data)
 
2197
        self.assertEqual(
 
2198
            1, decoder.next_read_size(),
 
2199
            "next_read_size hint should be 1 when finished_reading.")
 
2200
 
 
2201
    def test_multidigit_length(self):
 
2202
        """Lengths in the chunk prefixes can have multiple digits."""
 
2203
        decoder = protocol.ChunkedBodyDecoder()
 
2204
        decoder.accept_bytes('chunked\n')
 
2205
        length = 0x123
 
2206
        chunk_prefix = hex(length) + '\n'
 
2207
        chunk_bytes = 'z' * length
 
2208
        finish = 'END\n'
 
2209
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
 
2210
        self.assertTrue(decoder.finished_reading)
 
2211
        self.assertEqual(chunk_bytes, decoder.read_next_chunk())
 
2212
 
 
2213
    def test_byte_at_a_time(self):
 
2214
        """A complete body fed to the decoder one byte at a time should not
 
2215
        confuse the decoder.  That is, it should give the same result as if the
 
2216
        bytes had been received in one batch.
 
2217
 
 
2218
        This test is the same as test_one_chunk apart from the way accept_bytes
 
2219
        is called.
 
2220
        """
 
2221
        decoder = protocol.ChunkedBodyDecoder()
 
2222
        decoder.accept_bytes('chunked\n')
 
2223
        chunk_length = 'f\n'
 
2224
        chunk_content = '123456789abcdef'
 
2225
        finish = 'END\n'
 
2226
        for byte in (chunk_length + chunk_content + finish):
 
2227
            decoder.accept_bytes(byte)
 
2228
        self.assertTrue(decoder.finished_reading)
 
2229
        self.assertEqual(chunk_content, decoder.read_next_chunk())
 
2230
        self.assertEqual('', decoder.unused_data)
 
2231
 
 
2232
    def test_read_pending_data_resets(self):
 
2233
        """read_pending_data does not return the same bytes twice."""
 
2234
        decoder = protocol.ChunkedBodyDecoder()
 
2235
        decoder.accept_bytes('chunked\n')
 
2236
        chunk_one = '3\naaa'
 
2237
        chunk_two = '3\nbbb'
 
2238
        finish = 'END\n'
 
2239
        decoder.accept_bytes(chunk_one)
 
2240
        self.assertEqual('aaa', decoder.read_next_chunk())
 
2241
        decoder.accept_bytes(chunk_two)
 
2242
        self.assertEqual('bbb', decoder.read_next_chunk())
 
2243
        self.assertEqual(None, decoder.read_next_chunk())
 
2244
 
 
2245
    def test_decode_error(self):
 
2246
        decoder = protocol.ChunkedBodyDecoder()
 
2247
        decoder.accept_bytes('chunked\n')
 
2248
        chunk_one = 'b\nfirst chunk'
 
2249
        error_signal = 'ERR\n'
 
2250
        error_chunks = '5\npart1' + '5\npart2'
 
2251
        finish = 'END\n'
 
2252
        decoder.accept_bytes(chunk_one + error_signal + error_chunks + finish)
 
2253
        self.assertTrue(decoder.finished_reading)
 
2254
        self.assertEqual('first chunk', decoder.read_next_chunk())
 
2255
        expected_failure = request.FailedSmartServerResponse(
 
2256
            ('part1', 'part2'))
 
2257
        self.assertEqual(expected_failure, decoder.read_next_chunk())
 
2258
 
 
2259
    def test_bad_header(self):
 
2260
        """accept_bytes raises a SmartProtocolError if a chunked body does not
 
2261
        start with the right header.
 
2262
        """
 
2263
        decoder = protocol.ChunkedBodyDecoder()
 
2264
        self.assertRaises(
 
2265
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
 
2266
 
 
2267
 
2004
2268
class TestSuccessfulSmartServerResponse(tests.TestCase):
2005
2269
 
2006
 
    def test_construct(self):
 
2270
    def test_construct_no_body(self):
2007
2271
        response = request.SuccessfulSmartServerResponse(('foo', 'bar'))
2008
2272
        self.assertEqual(('foo', 'bar'), response.args)
2009
2273
        self.assertEqual(None, response.body)
2010
 
        response = request.SuccessfulSmartServerResponse(('foo', 'bar'), 'bytes')
 
2274
 
 
2275
    def test_construct_with_body(self):
 
2276
        response = request.SuccessfulSmartServerResponse(
 
2277
            ('foo', 'bar'), 'bytes')
2011
2278
        self.assertEqual(('foo', 'bar'), response.args)
2012
2279
        self.assertEqual('bytes', response.body)
2013
2280
 
 
2281
    def test_construct_with_body_stream(self):
 
2282
        bytes_iterable = ['abc']
 
2283
        response = request.SuccessfulSmartServerResponse(
 
2284
            ('foo', 'bar'), body_stream=bytes_iterable)
 
2285
        self.assertEqual(('foo', 'bar'), response.args)
 
2286
        self.assertEqual(bytes_iterable, response.body_stream)
 
2287
 
 
2288
    def test_construct_rejects_body_and_body_stream(self):
 
2289
        """'body' and 'body_stream' are mutually exclusive."""
 
2290
        self.assertRaises(
 
2291
            errors.BzrError,
 
2292
            request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
 
2293
 
2014
2294
    def test_is_successful(self):
2015
2295
        """is_successful should return True for SuccessfulSmartServerResponse."""
2016
2296
        response = request.SuccessfulSmartServerResponse(('error',))