124
124
returncode = child.wait()
125
125
self.assertEquals(0, returncode)
127
def test_serialize_offsets(self):
128
def check(expected, offsets):
129
value = smart.SmartTransport._serialise_offsets(offsets)
130
self.assertEqual(expected, value)
132
check('1,2', [(1,2)])
133
check('1,2\n3,4', [(1,2), (3,4)])
134
check('1,2\n3,4\n100,200', [(1,2), (3,4), (100, 200)])
136
def test_deserialise_offsets(self):
137
def check(expected, text):
138
offsets = smart.SmartServer._deserialise_offsets(text)
139
self.assertEqual(expected, offsets)
141
check([(1,2)], '1,2')
142
check([(1,2), (3,4)], '1,2\n3,4')
143
check([(1,2), (3,4), (100, 200)], '1,2\n3,4\n100,200')
146
128
class SmartTCPTests(tests.TestCase):
147
129
"""Tests for connection to TCP server.
294
276
self.assertEqual([('_call', ('get', '/foo'))], client._calls)
279
class InstrumentedClient(smart.SmartStreamClient):
280
"""A smart client whose writes are stored to a supplied list."""
282
def __init__(self, write_output_list):
283
smart.SmartStreamClient.__init__(self, None)
284
self._write_output_list = write_output_list
286
def _ensure_connection(self):
287
"""We are never strictly connected."""
289
def _write_and_flush(self, bytes):
290
self._write_output_list.append(bytes)
293
class InstrumentedServerProtocol(smart.SmartStreamServer):
294
"""A smart server which is backed by memory and saves its write requests."""
296
def __init__(self, write_output_list):
297
smart.SmartStreamServer.__init__(self, None, None,
298
memory.MemoryTransport())
299
self._write_output_list = write_output_list
301
def _write_and_flush(self, bytes):
302
self._write_output_list.append(bytes)
305
class TestSmartProtocol(tests.TestCase):
306
"""Tests for the smart protocol.
308
Each test case gets a smart_server and smart_client created during setUp().
310
It is planned that the client can be called with self.call_client() giving
311
it an expected server response, which will be fed into it when it tries to
312
read. Likewise, self.call_server will call a servers method with a canned
313
serialised client request. Output done by the client or server for these
314
calls will be captured to self.to_server and self.to_client. Each element
315
in the list is a write call from the client or server respectively.
319
super(TestSmartProtocol, self).setUp()
322
self.smart_client = InstrumentedClient(self.to_server)
323
self.smart_server = InstrumentedServerProtocol(self.to_client)
325
def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
326
client, server_protocol):
327
"""Check that smart (de)serialises offsets as expected.
329
We check both serialisation and deserialisation at the same time
330
to ensure that the round tripping cannot skew: both directions should
333
:param expected_offsets: a readv offset list.
334
:param expected_seralised: an expected serial form of the offsets.
335
:param server: a SmartServer instance.
337
offsets = server_protocol.smart_server._deserialise_offsets(
339
self.assertEqual(expected_offsets, offsets)
340
serialised = client._serialise_offsets(offsets)
341
self.assertEqual(expected_serialised, serialised)
343
def test_server_offset_serialisation(self):
344
"""The Smart protocol serialises offsets as a comma and \n string.
346
We check a number of boundary cases are as expected: empty, one offset,
347
one with the order of reads not increasing (an out of order read), and
348
one that should coalesce.
350
self.assertOffsetSerialisation([], '',
351
self.smart_client, self.smart_server)
352
self.assertOffsetSerialisation([(1,2)], '1,2',
353
self.smart_client, self.smart_server)
354
self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
355
self.smart_client, self.smart_server)
356
self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
357
'1,2\n3,4\n100,200', self.smart_client, self.smart_server)
297
360
# TODO: Client feature that does get_bundle and then installs that into a
298
361
# branch; this can be used in place of the regular pull/fetch operation when
299
362
# coming from a smart server.