~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart_transport.py

Use the Command pattern for smart server request handling

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
        protocol,
36
36
        request,
37
37
        server,
 
38
        vfs,
38
39
)
39
40
from bzrlib.tests.HTTPTestUtil import (
40
41
        HTTPServerWithSmarts,
574
575
 
575
576
class TestSmartServerStreamMedium(tests.TestCase):
576
577
 
 
578
    def setUp(self):
 
579
        super(TestSmartServerStreamMedium, self).setUp()
 
580
        self._captureVar('BZR_NO_SMART_VFS', None)
 
581
 
577
582
    def portable_socket_pair(self):
578
583
        """Return a pair of TCP sockets connected to each other.
579
584
        
780
785
 
781
786
    def test_get_error_unexpected(self):
782
787
        """Error reported by server with no specific representation"""
 
788
        self._captureVar('BZR_NO_SMART_VFS', None)
783
789
        class FlakyTransport(object):
784
790
            base = 'a_url'
785
791
            def get_bytes(self, path):
865
871
 
866
872
    def test_smart_transport_has(self):
867
873
        """Checking for file existence over smart."""
 
874
        self._captureVar('BZR_NO_SMART_VFS', None)
868
875
        self.backing_transport.put_bytes("foo", "contents of foo\n")
869
876
        self.assertTrue(self.transport.has("foo"))
870
877
        self.assertFalse(self.transport.has("non-foo"))
871
878
 
872
879
    def test_smart_transport_get(self):
873
880
        """Read back a file over smart."""
 
881
        self._captureVar('BZR_NO_SMART_VFS', None)
874
882
        self.backing_transport.put_bytes("foo", "contents\nof\nfoo\n")
875
883
        fp = self.transport.get("foo")
876
884
        self.assertEqual('contents\nof\nfoo\n', fp.read())
880
888
        # The path in a raised NoSuchFile exception should be the precise path
881
889
        # asked for by the client. This gives meaningful and unsurprising errors
882
890
        # for users.
 
891
        self._captureVar('BZR_NO_SMART_VFS', None)
883
892
        try:
884
893
            self.transport.get('not%20a%20file')
885
894
        except errors.NoSuchFile, e:
906
915
 
907
916
    def test_open_dir(self):
908
917
        """Test changing directory"""
 
918
        self._captureVar('BZR_NO_SMART_VFS', None)
909
919
        transport = self.transport
910
920
        self.backing_transport.mkdir('toffee')
911
921
        self.backing_transport.mkdir('toffee/apple')
933
943
 
934
944
    def test_mkdir_error_readonly(self):
935
945
        """TransportNotPossible should be preserved from the backing transport."""
 
946
        self._captureVar('BZR_NO_SMART_VFS', None)
936
947
        self.setUpServer(readonly=True)
937
948
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
938
949
            'foo')
977
988
# server-stopped hook.
978
989
 
979
990
 
980
 
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
981
 
    """Test that call directly into the handler logic, bypassing the network."""
982
 
 
983
 
    def test_construct_request_handler(self):
984
 
        """Constructing a request handler should be easy and set defaults."""
985
 
        handler = request.SmartServerRequestHandler(None)
986
 
        self.assertFalse(handler.finished_reading)
987
 
 
 
991
class SmartServerCommandTests(tests.TestCaseWithTransport):
 
992
    """Tests that call directly into the command objects, bypassing the network
 
993
    and the request dispatching.
 
994
    """
 
995
        
988
996
    def test_hello(self):
989
 
        handler = request.SmartServerRequestHandler(None)
990
 
        handler.dispatch_command('hello', ())
991
 
        self.assertEqual(('ok', '1'), handler.response.args)
992
 
        self.assertEqual(None, handler.response.body)
 
997
        cmd = request.HelloRequest(None)
 
998
        response = cmd.execute()
 
999
        self.assertEqual(('ok', '1'), response.args)
 
1000
        self.assertEqual(None, response.body)
993
1001
        
994
1002
    def test_get_bundle(self):
995
1003
        from bzrlib.bundle import serializer
998
1006
        wt.add('hello')
999
1007
        rev_id = wt.commit('add hello')
1000
1008
        
1001
 
        handler = request.SmartServerRequestHandler(self.get_transport())
1002
 
        handler.dispatch_command('get_bundle', ('.', rev_id))
1003
 
        bundle = serializer.read_bundle(StringIO(handler.response.body))
1004
 
        self.assertEqual((), handler.response.args)
 
1009
        cmd = request.GetBundleRequest(self.get_transport())
 
1010
        response = cmd.execute('.', rev_id)
 
1011
        bundle = serializer.read_bundle(StringIO(response.body))
 
1012
        self.assertEqual((), response.args)
 
1013
 
 
1014
 
 
1015
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
 
1016
    """Test that call directly into the handler logic, bypassing the network."""
 
1017
 
 
1018
    def setUp(self):
 
1019
        super(SmartServerRequestHandlerTests, self).setUp()
 
1020
        self._captureVar('BZR_NO_SMART_VFS', None)
 
1021
 
 
1022
    def build_handler(self, transport):
 
1023
        """Returns a handler for the commands in protocol version one."""
 
1024
        return request.SmartServerRequestHandler(transport, request.request_handlers)
 
1025
 
 
1026
    def test_construct_request_handler(self):
 
1027
        """Constructing a request handler should be easy and set defaults."""
 
1028
        handler = request.SmartServerRequestHandler(None, None)
 
1029
        self.assertFalse(handler.finished_reading)
 
1030
 
 
1031
    def test_hello(self):
 
1032
        handler = self.build_handler(None)
 
1033
        handler.dispatch_command('hello', ())
 
1034
        self.assertEqual(('ok', '1'), handler.response.args)
 
1035
        self.assertEqual(None, handler.response.body)
 
1036
        
 
1037
    def test_disable_vfs_handler_classes_via_environment(self):
 
1038
        # VFS handler classes will raise an error from "execute" if BZR_NO_SMART_VFS
 
1039
        # is set.
 
1040
        handler = vfs.HasRequest(None)
 
1041
        # set environment variable after construction to make sure it's
 
1042
        # examined.
 
1043
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp has
 
1044
        # called _captureVar, so it will be restored to the right state
 
1045
        # afterwards.
 
1046
        os.environ['BZR_NO_SMART_VFS'] = ''
 
1047
        self.assertRaises(errors.DisabledMethod, handler.execute)
1005
1048
 
1006
1049
    def test_readonly_exception_becomes_transport_not_possible(self):
1007
1050
        """The response for a read-only error is ('ReadOnlyError')."""
1008
 
        handler = request.SmartServerRequestHandler(self.get_readonly_transport())
 
1051
        handler = self.build_handler(self.get_readonly_transport())
1009
1052
        # send a mkdir for foo, with no explicit mode - should fail.
1010
1053
        handler.dispatch_command('mkdir', ('foo', ''))
1011
1054
        # and the failure should be an explicit ReadOnlyError
1017
1060
 
1018
1061
    def test_hello_has_finished_body_on_dispatch(self):
1019
1062
        """The 'hello' command should set finished_reading."""
1020
 
        handler = request.SmartServerRequestHandler(None)
 
1063
        handler = self.build_handler(None)
1021
1064
        handler.dispatch_command('hello', ())
1022
1065
        self.assertTrue(handler.finished_reading)
1023
1066
        self.assertNotEqual(None, handler.response)
1024
1067
 
1025
1068
    def test_put_bytes_non_atomic(self):
1026
1069
        """'put_...' should set finished_reading after reading the bytes."""
1027
 
        handler = request.SmartServerRequestHandler(self.get_transport())
 
1070
        handler = self.build_handler(self.get_transport())
1028
1071
        handler.dispatch_command('put_non_atomic', ('a-file', '', 'F', ''))
1029
1072
        self.assertFalse(handler.finished_reading)
1030
1073
        handler.accept_body('1234')
1038
1081
    def test_readv_accept_body(self):
1039
1082
        """'readv' should set finished_reading after reading offsets."""
1040
1083
        self.build_tree(['a-file'])
1041
 
        handler = request.SmartServerRequestHandler(self.get_readonly_transport())
 
1084
        handler = self.build_handler(self.get_readonly_transport())
1042
1085
        handler.dispatch_command('readv', ('a-file', ))
1043
1086
        self.assertFalse(handler.finished_reading)
1044
1087
        handler.accept_body('2,')
1053
1096
    def test_readv_short_read_response_contents(self):
1054
1097
        """'readv' when a short read occurs sets the response appropriately."""
1055
1098
        self.build_tree(['a-file'])
1056
 
        handler = request.SmartServerRequestHandler(self.get_readonly_transport())
 
1099
        handler = self.build_handler(self.get_readonly_transport())
1057
1100
        handler.dispatch_command('readv', ('a-file', ))
1058
1101
        # read beyond the end of the file.
1059
1102
        handler.accept_body('100,1')
1138
1181
        self.client_protocol = protocol.SmartClientRequestProtocolOne(
1139
1182
            self.client_medium)
1140
1183
        self.smart_server = InstrumentedServerProtocol(self.server_to_client)
1141
 
        self.smart_server_request = request.SmartServerRequestHandler(None)
 
1184
        self.smart_server_request = request.SmartServerRequestHandler(
 
1185
            None, request.request_handlers)
1142
1186
 
1143
1187
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
1144
 
        client, smart_server_request):
 
1188
        client):
1145
1189
        """Check that smart (de)serialises offsets as expected.
1146
1190
        
1147
1191
        We check both serialisation and deserialisation at the same time
1150
1194
        
1151
1195
        :param expected_offsets: a readv offset list.
1152
1196
        :param expected_seralised: an expected serial form of the offsets.
1153
 
        :param smart_server_request: a SmartServerRequestHandler instance.
1154
1197
        """
1155
 
        # XXX: 'smart_server_request' should be a SmartServerRequestProtocol in
1156
 
        # future.
1157
 
        offsets = smart_server_request._deserialise_offsets(expected_serialised)
 
1198
        # XXX: '_deserialise_offsets' should be a method of the
 
1199
        # SmartServerRequestProtocol in future.
 
1200
        readv_cmd = vfs.ReadvRequest(None)
 
1201
        offsets = readv_cmd._deserialise_offsets(expected_serialised)
1158
1202
        self.assertEqual(expected_offsets, offsets)
1159
1203
        serialised = client._serialise_offsets(offsets)
1160
1204
        self.assertEqual(expected_serialised, serialised)
1161
1205
 
1162
1206
    def build_protocol_waiting_for_body(self):
1163
1207
        out_stream = StringIO()
1164
 
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, out_stream.write)
 
1208
        smart_protocol = protocol.SmartServerRequestProtocolOne(None,
 
1209
                out_stream.write)
1165
1210
        smart_protocol.has_dispatched = True
1166
 
        smart_protocol.request = request.SmartServerRequestHandler(None)
1167
 
        def handle_end_of_bytes():
1168
 
            self.end_received = True
1169
 
            self.assertEqual('abcdefg', smart_protocol.request._body_bytes)
1170
 
            smart_protocol.request.response = request.SmartServerResponse(('ok', ))
1171
 
        smart_protocol.request._end_of_body_handler = handle_end_of_bytes
 
1211
        smart_protocol.request = self.smart_server_request
 
1212
        class FakeCommand(object):
 
1213
            def do_body(cmd, body_bytes):
 
1214
                self.end_received = True
 
1215
                self.assertEqual('abcdefg', body_bytes)
 
1216
                return request.SmartServerResponse(('ok', ))
 
1217
        smart_protocol.request._command = FakeCommand()
1172
1218
        # Call accept_bytes to make sure that internal state like _body_decoder
1173
1219
        # is initialised.  This test should probably be given a clearer
1174
1220
        # interface to work with that will not cause this inconsistency.
1197
1243
        one with the order of reads not increasing (an out of order read), and
1198
1244
        one that should coalesce.
1199
1245
        """
1200
 
        self.assertOffsetSerialisation([], '',
1201
 
            self.client_protocol, self.smart_server_request)
1202
 
        self.assertOffsetSerialisation([(1,2)], '1,2',
1203
 
            self.client_protocol, self.smart_server_request)
 
1246
        self.assertOffsetSerialisation([], '', self.client_protocol)
 
1247
        self.assertOffsetSerialisation([(1,2)], '1,2', self.client_protocol)
1204
1248
        self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
1205
 
            self.client_protocol, self.smart_server_request)
 
1249
            self.client_protocol)
1206
1250
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1207
 
            '1,2\n3,4\n100,200', self.client_protocol, self.smart_server_request)
 
1251
            '1,2\n3,4\n100,200', self.client_protocol)
1208
1252
 
1209
1253
    def test_accept_bytes_of_bad_request_to_protocol(self):
1210
1254
        out_stream = StringIO()
1230
1274
        self.assertTrue(self.end_received)
1231
1275
 
1232
1276
    def test_accept_request_and_body_all_at_once(self):
1233
 
        self._captureVar('NO_SMART_VFS', None)
 
1277
        self._captureVar('BZR_NO_SMART_VFS', None)
1234
1278
        mem_transport = memory.MemoryTransport()
1235
1279
        mem_transport.put_bytes('foo', 'abcdefghij')
1236
1280
        out_stream = StringIO()
1488
1532
    def setUp(self):
1489
1533
        super(HTTPTunnellingSmokeTest, self).setUp()
1490
1534
        # We use the VFS layer as part of HTTP tunnelling tests.
1491
 
        self._captureVar('NO_SMART_VFS', None)
 
1535
        self._captureVar('BZR_NO_SMART_VFS', None)
1492
1536
 
1493
1537
    def _test_bulk_data(self, url_protocol):
1494
1538
        # We should be able to send and receive bulk data in a single message.