1661
1661
self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1662
1662
'1,2\n3,4\n100,200', self.client_protocol)
1664
def assertBodyStreamSerialisation(self, expected_serialisation,
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())
1671
def assertBodyStreamRoundTrips(self, body_stream):
1672
"""Assert that body_stream is the same after being serialised and
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)
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([])
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' +
1693
self.assertBodyStreamRoundTrips(stream)
1695
def test_body_stream_with_empty_element_serialisation(self):
1696
"""A body stream can include ''.
1698
The empty string can be transmitted like any other string.
1700
stream = ['', 'chunk']
1701
self.assertBodyStreamSerialisation(
1702
'chunked\n' + '0\n' + '5\nchunk' + 'END\n', stream)
1703
self.assertBodyStreamRoundTrips(stream)
1705
def test_body_stream_error_serialistion(self):
1706
stream = ['first chunk',
1707
request.FailedSmartServerResponse(
1708
('FailureName', 'failure arg'))]
1710
'chunked\n' + 'b\nfirst chunk' +
1711
'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
1713
self.assertBodyStreamSerialisation(expected_bytes, stream)
1714
self.assertBodyStreamRoundTrips(stream)
1664
1716
def test_accept_bytes_of_bad_request_to_protocol(self):
1665
1717
out_stream = StringIO()
1666
1718
smart_protocol = protocol.SmartServerRequestProtocolTwo(
1896
1955
self.assertRaises(
1897
1956
errors.ReadingCompleted, smart_protocol.read_body_bytes)
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 +
1965
input = StringIO(server_bytes)
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))
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'
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)
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)
1994
request.FailedSmartServerResponse(('error arg1', 'arg2'))]
1995
stream = smart_protocol.read_streamed_body()
1996
self.assertEqual(expected_chunks, list(stream))
1900
1999
class TestSmartClientUnicode(tests.TestCase):
1901
2000
"""_SmartClient tests for unicode arguments.
2001
2100
self.assertEqual('', decoder.unused_data)
2103
class TestChunkedBodyDecoder(tests.TestCase):
2104
"""Tests for ChunkedBodyDecoder.
2106
This is the body decoder used for protocol version two.
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)
2116
def test_empty_content(self):
2117
"""'chunked\nEND\n' is the complete encoding of a zero-length body.
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)
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'
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)
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.
2142
decoder = protocol.ChunkedBodyDecoder()
2143
decoder.accept_bytes('chunked\n')
2144
chunk_length = '8\n'
2146
decoder.accept_bytes(chunk_length + three_bytes)
2147
self.assertFalse(decoder.finished_reading)
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: "
2153
self.assertEqual(None, decoder.read_next_chunk())
2155
def test_incomplete_length(self):
2156
"""A chunk length hasn't been read until a newline byte has been read.
2158
decoder = protocol.ChunkedBodyDecoder()
2159
decoder.accept_bytes('chunked\n')
2160
decoder.accept_bytes('9')
2162
1, decoder.next_read_size(),
2163
"The next_read_size hint should be 1, because we don't know the "
2165
decoder.accept_bytes('\n')
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())
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'
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)
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)
2198
1, decoder.next_read_size(),
2199
"next_read_size hint should be 1 when finished_reading.")
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')
2206
chunk_prefix = hex(length) + '\n'
2207
chunk_bytes = 'z' * length
2209
decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
2210
self.assertTrue(decoder.finished_reading)
2211
self.assertEqual(chunk_bytes, decoder.read_next_chunk())
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.
2218
This test is the same as test_one_chunk apart from the way accept_bytes
2221
decoder = protocol.ChunkedBodyDecoder()
2222
decoder.accept_bytes('chunked\n')
2223
chunk_length = 'f\n'
2224
chunk_content = '123456789abcdef'
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)
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'
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())
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'
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(
2257
self.assertEqual(expected_failure, decoder.read_next_chunk())
2259
def test_bad_header(self):
2260
"""accept_bytes raises a SmartProtocolError if a chunked body does not
2261
start with the right header.
2263
decoder = protocol.ChunkedBodyDecoder()
2265
errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
2004
2268
class TestSuccessfulSmartServerResponse(tests.TestCase):
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')
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)
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)
2288
def test_construct_rejects_body_and_body_stream(self):
2289
"""'body' and 'body_stream' are mutually exclusive."""
2292
request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2014
2294
def test_is_successful(self):
2015
2295
"""is_successful should return True for SuccessfulSmartServerResponse."""
2016
2296
response = request.SuccessfulSmartServerResponse(('error',))