/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1
# Copyright (C) 2006, 2007 Canonical Ltd
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for smart transport"""
18
19
# all of this deals with byte strings so this is safe
20
from cStringIO import StringIO
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
21
import os
22
import socket
23
import threading
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
24
import urllib2
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
25
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
26
from bzrlib import (
27
        bzrdir,
28
        errors,
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
29
        osutils,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
30
        tests,
2049.1.1 by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes.
31
        urlutils,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
32
        )
2018.5.21 by Andrew Bennetts
Move bzrlib.transport.smart to bzrlib.smart
33
from bzrlib.smart import (
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
34
        client,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
35
        medium,
36
        protocol,
2432.4.3 by Robert Collins
Refactor the HPSS Response code to take SmartServerResponse rather than args and body.
37
        request as _mod_request,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
38
        server,
39
        vfs,
40
)
3102.1.1 by Vincent Ladeuil
Rename bzrlib/test/HTTPTestUtils.py to bzrlib/tests/http_utils.py and fix
41
from bzrlib.tests.http_utils import (
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
42
        HTTPServerWithSmarts,
43
        SmartRequestHandler,
44
        )
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
45
from bzrlib.tests.test_smart import TestCaseWithSmartMedium
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
46
from bzrlib.transport import (
47
        get_transport,
48
        local,
49
        memory,
2400.1.1 by Andrew Bennetts
Rename bzrlib/transport/smart.py to bzrlib/transport/remote.py.
50
        remote,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
51
        )
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
52
from bzrlib.transport.http import SmartClientHTTPMediumRequest
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
53
54
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
55
class StringIOSSHVendor(object):
56
    """A SSH vendor that uses StringIO to buffer writes and answer reads."""
57
58
    def __init__(self, read_from, write_to):
59
        self.read_from = read_from
60
        self.write_to = write_to
61
        self.calls = []
62
63
    def connect_ssh(self, username, password, host, port, command):
64
        self.calls.append(('connect_ssh', username, password, host, port,
65
            command))
66
        return StringIOSSHConnection(self)
67
68
69
class StringIOSSHConnection(object):
70
    """A SSH connection that uses StringIO to buffer writes and answer reads."""
71
72
    def __init__(self, vendor):
73
        self.vendor = vendor
74
    
75
    def close(self):
76
        self.vendor.calls.append(('close', ))
77
        
78
    def get_filelike_channels(self):
79
        return self.vendor.read_from, self.vendor.write_to
80
81
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
82
class _InvalidHostnameFeature(tests.Feature):
83
    """Does 'non_existent.invalid' fail to resolve?
84
    
85
    RFC 2606 states that .invalid is reserved for invalid domain names, and
86
    also underscores are not a valid character in domain names.  Despite this,
87
    it's possible a badly misconfigured name server might decide to always
88
    return an address for any name, so this feature allows us to distinguish a
89
    broken system from a broken test.
90
    """
91
92
    def _probe(self):
93
        try:
94
            socket.gethostbyname('non_existent.invalid')
95
        except socket.gaierror:
96
            # The host name failed to resolve.  Good.
97
            return True
98
        else:
99
            return False
100
101
    def feature_name(self):
102
        return 'invalid hostname'
103
104
InvalidHostnameFeature = _InvalidHostnameFeature()
105
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
106
107
class SmartClientMediumTests(tests.TestCase):
108
    """Tests for SmartClientMedium.
109
110
    We should create a test scenario for this: we need a server module that
111
    construct the test-servers (like make_loopsocket_and_medium), and the list
112
    of SmartClientMedium classes to test.
113
    """
114
115
    def make_loopsocket_and_medium(self):
116
        """Create a loopback socket for testing, and a medium aimed at it."""
117
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
118
        sock.bind(('127.0.0.1', 0))
119
        sock.listen(1)
120
        port = sock.getsockname()[1]
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
121
        client_medium = medium.SmartTCPClientMedium('127.0.0.1', port)
122
        return sock, client_medium
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
123
124
    def receive_bytes_on_server(self, sock, bytes):
125
        """Accept a connection on sock and read 3 bytes.
126
127
        The bytes are appended to the list bytes.
128
129
        :return: a Thread which is running to do the accept and recv.
130
        """
131
        def _receive_bytes_on_server():
132
            connection, address = sock.accept()
2091.1.1 by Martin Pool
Avoid MSG_WAITALL as it doesn't work on Windows
133
            bytes.append(osutils.recv_all(connection, 3))
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
134
            connection.close()
135
        t = threading.Thread(target=_receive_bytes_on_server)
136
        t.start()
137
        return t
138
    
139
    def test_construct_smart_stream_medium_client(self):
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
140
        # make a new instance of the common base for Stream-like Mediums.
141
        # this just ensures that the constructor stays parameter-free which
142
        # is important for reuse : some subclasses will dynamically connect,
143
        # others are always on, etc.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
144
        client_medium = medium.SmartClientStreamMedium()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
145
146
    def test_construct_smart_client_medium(self):
147
        # the base client medium takes no parameters
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
148
        client_medium = medium.SmartClientMedium()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
149
    
150
    def test_construct_smart_simple_pipes_client_medium(self):
151
        # the SimplePipes client medium takes two pipes:
152
        # readable pipe, writeable pipe.
153
        # Constructing one should just save these and do nothing.
154
        # We test this by passing in None.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
155
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
156
        
157
    def test_simple_pipes_client_request_type(self):
158
        # SimplePipesClient should use SmartClientStreamMediumRequest's.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
159
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
160
        request = client_medium.get_request()
161
        self.assertIsInstance(request, medium.SmartClientStreamMediumRequest)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
162
163
    def test_simple_pipes_client_get_concurrent_requests(self):
164
        # the simple_pipes client does not support pipelined requests:
165
        # but it does support serial requests: we construct one after 
166
        # another is finished. This is a smoke test testing the integration
167
        # of the SmartClientStreamMediumRequest and the SmartClientStreamMedium
168
        # classes - as the sibling classes share this logic, they do not have
169
        # explicit tests for this.
170
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
171
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
172
        request = client_medium.get_request()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
173
        request.finished_writing()
174
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
175
        request2 = client_medium.get_request()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
176
        request2.finished_writing()
177
        request2.finished_reading()
178
179
    def test_simple_pipes_client__accept_bytes_writes_to_writable(self):
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
180
        # accept_bytes writes to the writeable pipe.
181
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
182
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
183
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
184
        self.assertEqual('abc', output.getvalue())
185
    
186
    def test_simple_pipes_client_disconnect_does_nothing(self):
187
        # calling disconnect does nothing.
188
        input = StringIO()
189
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
190
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
191
        # send some bytes to ensure disconnecting after activity still does not
192
        # close.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
193
        client_medium._accept_bytes('abc')
194
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
195
        self.assertFalse(input.closed)
196
        self.assertFalse(output.closed)
197
198
    def test_simple_pipes_client_accept_bytes_after_disconnect(self):
199
        # calling disconnect on the client does not alter the pipe that
200
        # accept_bytes writes to.
201
        input = StringIO()
202
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
203
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
204
        client_medium._accept_bytes('abc')
205
        client_medium.disconnect()
206
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
207
        self.assertFalse(input.closed)
208
        self.assertFalse(output.closed)
209
        self.assertEqual('abcabc', output.getvalue())
210
    
211
    def test_simple_pipes_client_ignores_disconnect_when_not_connected(self):
212
        # Doing a disconnect on a new (and thus unconnected) SimplePipes medium
213
        # does nothing.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
214
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
215
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
216
217
    def test_simple_pipes_client_can_always_read(self):
218
        # SmartSimplePipesClientMedium is never disconnected, so read_bytes
219
        # always tries to read from the underlying pipe.
220
        input = StringIO('abcdef')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
221
        client_medium = medium.SmartSimplePipesClientMedium(input, None)
222
        self.assertEqual('abc', client_medium.read_bytes(3))
223
        client_medium.disconnect()
224
        self.assertEqual('def', client_medium.read_bytes(3))
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
225
        
226
    def test_simple_pipes_client_supports__flush(self):
227
        # invoking _flush on a SimplePipesClient should flush the output 
228
        # pipe. We test this by creating an output pipe that records
229
        # flush calls made to it.
230
        from StringIO import StringIO # get regular StringIO
231
        input = StringIO()
232
        output = StringIO()
233
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
234
        def logging_flush(): flush_calls.append('flush')
235
        output.flush = logging_flush
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
236
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
237
        # this call is here to ensure we only flush once, not on every
238
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
239
        client_medium._accept_bytes('abc')
240
        client_medium._flush()
241
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
242
        self.assertEqual(['flush'], flush_calls)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
243
244
    def test_construct_smart_ssh_client_medium(self):
245
        # the SSH client medium takes:
246
        # host, port, username, password, vendor
247
        # Constructing one should just save these and do nothing.
248
        # we test this by creating a empty bound socket and constructing
249
        # a medium.
250
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
251
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
252
        unopened_port = sock.getsockname()[1]
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
253
        # having vendor be invalid means that if it tries to connect via the
254
        # vendor it will blow up.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
255
        client_medium = medium.SmartSSHClientMedium('127.0.0.1', unopened_port,
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
256
            username=None, password=None, vendor="not a vendor",
257
            bzr_remote_path='bzr')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
258
        sock.close()
259
260
    def test_ssh_client_connects_on_first_use(self):
261
        # The only thing that initiates a connection from the medium is giving
262
        # it bytes.
263
        output = StringIO()
264
        vendor = StringIOSSHVendor(StringIO(), output)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
265
        client_medium = medium.SmartSSHClientMedium(
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
266
            'a hostname', 'a port', 'a username', 'a password', vendor, 'bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
267
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
268
        self.assertEqual('abc', output.getvalue())
269
        self.assertEqual([('connect_ssh', 'a username', 'a password',
270
            'a hostname', 'a port',
271
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes'])],
272
            vendor.calls)
273
    
274
    def test_ssh_client_changes_command_when_BZR_REMOTE_PATH_is_set(self):
275
        # The only thing that initiates a connection from the medium is giving
276
        # it bytes.
277
        output = StringIO()
278
        vendor = StringIOSSHVendor(StringIO(), output)
279
        orig_bzr_remote_path = os.environ.get('BZR_REMOTE_PATH')
280
        def cleanup_environ():
281
            osutils.set_or_unset_env('BZR_REMOTE_PATH', orig_bzr_remote_path)
282
        self.addCleanup(cleanup_environ)
283
        os.environ['BZR_REMOTE_PATH'] = 'fugly'
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
284
        client_medium = self.callDeprecated(
285
            ['bzr_remote_path is required as of bzr 0.92'],
286
            medium.SmartSSHClientMedium, 'a hostname', 'a port', 'a username',
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
287
            'a password', vendor)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
288
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
289
        self.assertEqual('abc', output.getvalue())
290
        self.assertEqual([('connect_ssh', 'a username', 'a password',
291
            'a hostname', 'a port',
292
            ['fugly', 'serve', '--inet', '--directory=/', '--allow-writes'])],
293
            vendor.calls)
294
    
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
295
    def test_ssh_client_changes_command_when_bzr_remote_path_passed(self):
296
        # The only thing that initiates a connection from the medium is giving
297
        # it bytes.
298
        output = StringIO()
299
        vendor = StringIOSSHVendor(StringIO(), output)
300
        client_medium = medium.SmartSSHClientMedium('a hostname', 'a port',
301
            'a username', 'a password', vendor, bzr_remote_path='fugly')
302
        client_medium._accept_bytes('abc')
303
        self.assertEqual('abc', output.getvalue())
304
        self.assertEqual([('connect_ssh', 'a username', 'a password',
305
            'a hostname', 'a port',
306
            ['fugly', 'serve', '--inet', '--directory=/', '--allow-writes'])],
307
            vendor.calls)
308
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
309
    def test_ssh_client_disconnect_does_so(self):
310
        # calling disconnect should disconnect both the read_from and write_to
311
        # file-like object it from the ssh connection.
312
        input = StringIO()
313
        output = StringIO()
314
        vendor = StringIOSSHVendor(input, output)
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
315
        client_medium = medium.SmartSSHClientMedium('a hostname',
316
                                                    vendor=vendor,
317
                                                    bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
318
        client_medium._accept_bytes('abc')
319
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
320
        self.assertTrue(input.closed)
321
        self.assertTrue(output.closed)
322
        self.assertEqual([
323
            ('connect_ssh', None, None, 'a hostname', None,
324
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
325
            ('close', ),
326
            ],
327
            vendor.calls)
328
329
    def test_ssh_client_disconnect_allows_reconnection(self):
330
        # calling disconnect on the client terminates the connection, but should
331
        # not prevent additional connections occuring.
332
        # we test this by initiating a second connection after doing a
333
        # disconnect.
334
        input = StringIO()
335
        output = StringIO()
336
        vendor = StringIOSSHVendor(input, output)
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
337
        client_medium = medium.SmartSSHClientMedium('a hostname',
338
            vendor=vendor, bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
339
        client_medium._accept_bytes('abc')
340
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
341
        # the disconnect has closed output, so we need a new output for the
342
        # new connection to write to.
343
        input2 = StringIO()
344
        output2 = StringIO()
345
        vendor.read_from = input2
346
        vendor.write_to = output2
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
347
        client_medium._accept_bytes('abc')
348
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
349
        self.assertTrue(input.closed)
350
        self.assertTrue(output.closed)
351
        self.assertTrue(input2.closed)
352
        self.assertTrue(output2.closed)
353
        self.assertEqual([
354
            ('connect_ssh', None, None, 'a hostname', None,
355
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
356
            ('close', ),
357
            ('connect_ssh', None, None, 'a hostname', None,
358
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
359
            ('close', ),
360
            ],
361
            vendor.calls)
362
    
363
    def test_ssh_client_ignores_disconnect_when_not_connected(self):
364
        # Doing a disconnect on a new (and thus unconnected) SSH medium
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
365
        # does not fail.  It's ok to disconnect an unconnected medium.
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
366
        client_medium = medium.SmartSSHClientMedium(None,
367
                                                    bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
368
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
369
370
    def test_ssh_client_raises_on_read_when_not_connected(self):
371
        # Doing a read on a new (and thus unconnected) SSH medium raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
372
        # MediumNotConnected.
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
373
        client_medium = medium.SmartSSHClientMedium(None,
374
                                                    bzr_remote_path='bzr')
375
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
376
                          0)
377
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
378
                          1)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
379
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
380
    def test_ssh_client_supports__flush(self):
381
        # invoking _flush on a SSHClientMedium should flush the output 
382
        # pipe. We test this by creating an output pipe that records
383
        # flush calls made to it.
384
        from StringIO import StringIO # get regular StringIO
385
        input = StringIO()
386
        output = StringIO()
387
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
388
        def logging_flush(): flush_calls.append('flush')
389
        output.flush = logging_flush
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
390
        vendor = StringIOSSHVendor(input, output)
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
391
        client_medium = medium.SmartSSHClientMedium('a hostname',
392
                                                    vendor=vendor,
393
                                                    bzr_remote_path='bzr')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
394
        # this call is here to ensure we only flush once, not on every
395
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
396
        client_medium._accept_bytes('abc')
397
        client_medium._flush()
398
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
399
        self.assertEqual(['flush'], flush_calls)
400
        
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
401
    def test_construct_smart_tcp_client_medium(self):
402
        # the TCP client medium takes a host and a port.  Constructing it won't
403
        # connect to anything.
404
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
405
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
406
        unopened_port = sock.getsockname()[1]
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
407
        client_medium = medium.SmartTCPClientMedium('127.0.0.1', unopened_port)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
408
        sock.close()
409
410
    def test_tcp_client_connects_on_first_use(self):
411
        # The only thing that initiates a connection from the medium is giving
412
        # it bytes.
413
        sock, medium = self.make_loopsocket_and_medium()
414
        bytes = []
415
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
416
        medium.accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
417
        t.join()
418
        sock.close()
419
        self.assertEqual(['abc'], bytes)
420
    
421
    def test_tcp_client_disconnect_does_so(self):
422
        # calling disconnect on the client terminates the connection.
423
        # we test this by forcing a short read during a socket.MSG_WAITALL
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
424
        # call: write 2 bytes, try to read 3, and then the client disconnects.
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
425
        sock, medium = self.make_loopsocket_and_medium()
426
        bytes = []
427
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
428
        medium.accept_bytes('ab')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
429
        medium.disconnect()
430
        t.join()
431
        sock.close()
432
        self.assertEqual(['ab'], bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
433
        # now disconnect again: this should not do anything, if disconnection
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
434
        # really did disconnect.
435
        medium.disconnect()
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
436
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
437
    
438
    def test_tcp_client_ignores_disconnect_when_not_connected(self):
439
        # Doing a disconnect on a new (and thus unconnected) TCP medium
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
440
        # does not fail.  It's ok to disconnect an unconnected medium.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
441
        client_medium = medium.SmartTCPClientMedium(None, None)
442
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
443
444
    def test_tcp_client_raises_on_read_when_not_connected(self):
445
        # Doing a read on a new (and thus unconnected) TCP medium raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
446
        # MediumNotConnected.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
447
        client_medium = medium.SmartTCPClientMedium(None, None)
448
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 0)
449
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 1)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
450
451
    def test_tcp_client_supports__flush(self):
452
        # invoking _flush on a TCPClientMedium should do something useful.
453
        # RBC 20060922 not sure how to test/tell in this case.
454
        sock, medium = self.make_loopsocket_and_medium()
455
        bytes = []
456
        t = self.receive_bytes_on_server(sock, bytes)
457
        # try with nothing buffered
458
        medium._flush()
459
        medium._accept_bytes('ab')
460
        # and with something sent.
461
        medium._flush()
462
        medium.disconnect()
463
        t.join()
464
        sock.close()
465
        self.assertEqual(['ab'], bytes)
466
        # now disconnect again : this should not do anything, if disconnection
467
        # really did disconnect.
468
        medium.disconnect()
469
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
470
    def test_tcp_client_host_unknown_connection_error(self):
471
        self.requireFeature(InvalidHostnameFeature)
472
        client_medium = medium.SmartTCPClientMedium(
473
            'non_existent.invalid', 4155)
474
        self.assertRaises(
475
            errors.ConnectionError, client_medium._ensure_connection)
476
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
477
478
class TestSmartClientStreamMediumRequest(tests.TestCase):
479
    """Tests the for SmartClientStreamMediumRequest.
480
    
481
    SmartClientStreamMediumRequest is a helper for the three stream based 
482
    mediums: TCP, SSH, SimplePipes, so we only test it once, and then test that
483
    those three mediums implement the interface it expects.
484
    """
485
486
    def test_accept_bytes_after_finished_writing_errors(self):
487
        # calling accept_bytes after calling finished_writing raises 
488
        # WritingCompleted to prevent bad assumptions on stream environments
489
        # breaking the needs of message-based environments.
490
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
491
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
492
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
493
        request.finished_writing()
494
        self.assertRaises(errors.WritingCompleted, request.accept_bytes, None)
495
496
    def test_accept_bytes(self):
497
        # accept bytes should invoke _accept_bytes on the stream medium.
498
        # we test this by using the SimplePipes medium - the most trivial one
499
        # and checking that the pipes get the data.
500
        input = StringIO()
501
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
502
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
503
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
504
        request.accept_bytes('123')
505
        request.finished_writing()
506
        request.finished_reading()
507
        self.assertEqual('', input.getvalue())
508
        self.assertEqual('123', output.getvalue())
509
510
    def test_construct_sets_stream_request(self):
511
        # constructing a SmartClientStreamMediumRequest on a StreamMedium sets
512
        # the current request to the new SmartClientStreamMediumRequest
513
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
514
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
515
        request = medium.SmartClientStreamMediumRequest(client_medium)
516
        self.assertIs(client_medium._current_request, request)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
517
518
    def test_construct_while_another_request_active_throws(self):
519
        # constructing a SmartClientStreamMediumRequest on a StreamMedium with
520
        # a non-None _current_request raises TooManyConcurrentRequests.
521
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
522
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
523
        client_medium._current_request = "a"
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
524
        self.assertRaises(errors.TooManyConcurrentRequests,
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
525
            medium.SmartClientStreamMediumRequest, client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
526
527
    def test_finished_read_clears_current_request(self):
528
        # calling finished_reading clears the current request from the requests
529
        # medium
530
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
531
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
532
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
533
        request.finished_writing()
534
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
535
        self.assertEqual(None, client_medium._current_request)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
536
537
    def test_finished_read_before_finished_write_errors(self):
538
        # calling finished_reading before calling finished_writing triggers a
539
        # WritingNotComplete error.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
540
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
541
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
542
        self.assertRaises(errors.WritingNotComplete, request.finished_reading)
543
        
544
    def test_read_bytes(self):
545
        # read bytes should invoke _read_bytes on the stream medium.
546
        # we test this by using the SimplePipes medium - the most trivial one
547
        # and checking that the data is supplied. Its possible that a 
548
        # faulty implementation could poke at the pipe variables them selves,
549
        # but we trust that this will be caught as it will break the integration
550
        # smoke tests.
551
        input = StringIO('321')
552
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
553
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
554
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
555
        request.finished_writing()
556
        self.assertEqual('321', request.read_bytes(3))
557
        request.finished_reading()
558
        self.assertEqual('', input.read())
559
        self.assertEqual('', output.getvalue())
560
561
    def test_read_bytes_before_finished_write_errors(self):
562
        # calling read_bytes before calling finished_writing triggers a
563
        # WritingNotComplete error because the Smart protocol is designed to be
564
        # compatible with strict message based protocols like HTTP where the
565
        # request cannot be submitted until the writing has completed.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
566
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
567
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
568
        self.assertRaises(errors.WritingNotComplete, request.read_bytes, None)
569
570
    def test_read_bytes_after_finished_reading_errors(self):
571
        # calling read_bytes after calling finished_reading raises 
572
        # ReadingCompleted to prevent bad assumptions on stream environments
573
        # breaking the needs of message-based environments.
574
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
575
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
576
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
577
        request.finished_writing()
578
        request.finished_reading()
579
        self.assertRaises(errors.ReadingCompleted, request.read_bytes, None)
580
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
581
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
582
class RemoteTransportTests(TestCaseWithSmartMedium):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
583
584
    def test_plausible_url(self):
585
        self.assert_(self.get_url().startswith('bzr://'))
586
587
    def test_probe_transport(self):
588
        t = self.get_transport()
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
589
        self.assertIsInstance(t, remote.RemoteTransport)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
590
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
591
    def test_get_medium_from_transport(self):
592
        """Remote transport has a medium always, which it can return."""
593
        t = self.get_transport()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
594
        client_medium = t.get_smart_medium()
595
        self.assertIsInstance(client_medium, medium.SmartClientMedium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
596
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
597
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
598
class ErrorRaisingProtocol(object):
599
600
    def __init__(self, exception):
601
        self.exception = exception
602
603
    def next_read_size(self):
604
        raise self.exception
605
606
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
607
class SampleRequest(object):
608
    
609
    def __init__(self, expected_bytes):
610
        self.accepted_bytes = ''
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
611
        self._finished_reading = False
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
612
        self.expected_bytes = expected_bytes
613
        self.excess_buffer = ''
614
615
    def accept_bytes(self, bytes):
616
        self.accepted_bytes += bytes
617
        if self.accepted_bytes.startswith(self.expected_bytes):
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
618
            self._finished_reading = True
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
619
            self.excess_buffer = self.accepted_bytes[len(self.expected_bytes):]
620
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
621
    def next_read_size(self):
622
        if self._finished_reading:
623
            return 0
624
        else:
625
            return 1
626
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
627
628
class TestSmartServerStreamMedium(tests.TestCase):
629
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
630
    def setUp(self):
631
        super(TestSmartServerStreamMedium, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
632
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
633
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
634
    def portable_socket_pair(self):
635
        """Return a pair of TCP sockets connected to each other.
636
        
637
        Unlike socket.socketpair, this should work on Windows.
638
        """
639
        listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
640
        listen_sock.bind(('127.0.0.1', 0))
641
        listen_sock.listen(1)
642
        client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
643
        client_sock.connect(listen_sock.getsockname())
644
        server_sock, addr = listen_sock.accept()
645
        listen_sock.close()
646
        return server_sock, client_sock
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
647
    
648
    def test_smart_query_version(self):
649
        """Feed a canned query version to a server"""
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
650
        # wire-to-wire, using the whole stack
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
651
        to_server = StringIO('hello\n')
652
        from_server = StringIO()
2018.2.27 by Andrew Bennetts
Merge from bzr.dev
653
        transport = local.LocalTransport(urlutils.local_path_to_url('/'))
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
654
        server = medium.SmartServerPipeStreamMedium(
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
655
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
656
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
657
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
658
        server._serve_one_request(smart_protocol)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
659
        self.assertEqual('ok\0012\n',
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
660
                         from_server.getvalue())
661
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
662
    def test_response_to_canned_get(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
663
        transport = memory.MemoryTransport('memory:///')
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
664
        transport.put_bytes('testfile', 'contents\nof\nfile\n')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
665
        to_server = StringIO('get\001./testfile\n')
666
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
667
        server = medium.SmartServerPipeStreamMedium(
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
668
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
669
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
670
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
671
        server._serve_one_request(smart_protocol)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
672
        self.assertEqual('ok\n'
673
                         '17\n'
674
                         'contents\nof\nfile\n'
675
                         'done\n',
676
                         from_server.getvalue())
677
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
678
    def test_response_to_canned_get_of_utf8(self):
679
        # wire-to-wire, using the whole stack, with a UTF-8 filename.
680
        transport = memory.MemoryTransport('memory:///')
681
        utf8_filename = u'testfile\N{INTERROBANG}'.encode('utf-8')
682
        transport.put_bytes(utf8_filename, 'contents\nof\nfile\n')
683
        to_server = StringIO('get\001' + utf8_filename + '\n')
684
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
685
        server = medium.SmartServerPipeStreamMedium(
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
686
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
687
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
688
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
689
        server._serve_one_request(smart_protocol)
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
690
        self.assertEqual('ok\n'
691
                         '17\n'
692
                         'contents\nof\nfile\n'
693
                         'done\n',
694
                         from_server.getvalue())
695
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
696
    def test_pipe_like_stream_with_bulk_data(self):
697
        sample_request_bytes = 'command\n9\nbulk datadone\n'
698
        to_server = StringIO(sample_request_bytes)
699
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
700
        server = medium.SmartServerPipeStreamMedium(
701
            to_server, from_server, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
702
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
703
        server._serve_one_request(sample_protocol)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
704
        self.assertEqual('', from_server.getvalue())
705
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
706
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
707
708
    def test_socket_stream_with_bulk_data(self):
709
        sample_request_bytes = 'command\n9\nbulk datadone\n'
710
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
711
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
712
            server_sock, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
713
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
714
        client_sock.sendall(sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
715
        server._serve_one_request(sample_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
716
        server_sock.close()
717
        self.assertEqual('', client_sock.recv(1))
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
718
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
719
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
720
721
    def test_pipe_like_stream_shutdown_detection(self):
722
        to_server = StringIO('')
723
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
724
        server = medium.SmartServerPipeStreamMedium(to_server, from_server, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
725
        server._serve_one_request(SampleRequest('x'))
726
        self.assertTrue(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
727
        
728
    def test_socket_stream_shutdown_detection(self):
729
        server_sock, client_sock = self.portable_socket_pair()
730
        client_sock.close()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
731
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
732
            server_sock, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
733
        server._serve_one_request(SampleRequest('x'))
734
        self.assertTrue(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
735
        
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
736
    def test_socket_stream_incomplete_request(self):
737
        """The medium should still construct the right protocol version even if
738
        the initial read only reads part of the request.
739
740
        Specifically, it should correctly read the protocol version line even
741
        if the partial read doesn't end in a newline.  An older, naive
742
        implementation of _get_line in the server used to have a bug in that
743
        case.
744
        """
745
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
746
        rest_of_request_bytes = 'lo\n'
747
        expected_response = (
748
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
749
        server_sock, client_sock = self.portable_socket_pair()
750
        server = medium.SmartServerSocketStreamMedium(
751
            server_sock, None)
752
        client_sock.sendall(incomplete_request_bytes)
753
        server_protocol = server._build_protocol()
754
        client_sock.sendall(rest_of_request_bytes)
755
        server._serve_one_request(server_protocol)
756
        server_sock.close()
757
        self.assertEqual(expected_response, client_sock.recv(50),
758
                         "Not a version 2 response to 'hello' request.")
759
        self.assertEqual('', client_sock.recv(1))
760
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
761
    def test_pipe_stream_incomplete_request(self):
762
        """The medium should still construct the right protocol version even if
763
        the initial read only reads part of the request.
764
765
        Specifically, it should correctly read the protocol version line even
766
        if the partial read doesn't end in a newline.  An older, naive
767
        implementation of _get_line in the server used to have a bug in that
768
        case.
769
        """
770
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
771
        rest_of_request_bytes = 'lo\n'
772
        expected_response = (
773
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
774
        # Make a pair of pipes, to and from the server
775
        to_server, to_server_w = os.pipe()
776
        from_server_r, from_server = os.pipe()
777
        to_server = os.fdopen(to_server, 'r', 0)
778
        to_server_w = os.fdopen(to_server_w, 'w', 0)
779
        from_server_r = os.fdopen(from_server_r, 'r', 0)
780
        from_server = os.fdopen(from_server, 'w', 0)
781
        server = medium.SmartServerPipeStreamMedium(
782
            to_server, from_server, None)
783
        # Like test_socket_stream_incomplete_request, write an incomplete
784
        # request (that does not end in '\n') and build a protocol from it.
785
        to_server_w.write(incomplete_request_bytes)
786
        server_protocol = server._build_protocol()
787
        # Send the rest of the request, and finish serving it.
788
        to_server_w.write(rest_of_request_bytes)
789
        server._serve_one_request(server_protocol)
790
        to_server_w.close()
791
        from_server.close()
792
        self.assertEqual(expected_response, from_server_r.read(),
793
                         "Not a version 2 response to 'hello' request.")
794
        self.assertEqual('', from_server_r.read(1))
795
        from_server_r.close()
796
        to_server.close()
797
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
798
    def test_pipe_like_stream_with_two_requests(self):
799
        # If two requests are read in one go, then two calls to
800
        # _serve_one_request should still process both of them as if they had
801
        # been received seperately.
802
        sample_request_bytes = 'command\n'
803
        to_server = StringIO(sample_request_bytes * 2)
804
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
805
        server = medium.SmartServerPipeStreamMedium(
806
            to_server, from_server, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
807
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
808
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
809
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
810
        self.assertEqual('', from_server.getvalue())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
811
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
812
        # Make a new protocol, call _serve_one_request with it to collect the
813
        # second request.
814
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
815
        server._serve_one_request(second_protocol)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
816
        self.assertEqual('', from_server.getvalue())
817
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
818
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
819
        
820
    def test_socket_stream_with_two_requests(self):
821
        # If two requests are read in one go, then two calls to
822
        # _serve_one_request should still process both of them as if they had
823
        # been received seperately.
824
        sample_request_bytes = 'command\n'
825
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
826
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
827
            server_sock, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
828
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
829
        # Put two whole requests on the wire.
830
        client_sock.sendall(sample_request_bytes * 2)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
831
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
832
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
833
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
834
        # Make a new protocol, call _serve_one_request with it to collect the
835
        # second request.
836
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
837
        stream_still_open = server._serve_one_request(second_protocol)
838
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
839
        self.assertFalse(server.finished)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
840
        server_sock.close()
841
        self.assertEqual('', client_sock.recv(1))
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
842
843
    def test_pipe_like_stream_error_handling(self):
844
        # Use plain python StringIO so we can monkey-patch the close method to
845
        # not discard the contents.
846
        from StringIO import StringIO
847
        to_server = StringIO('')
848
        from_server = StringIO()
849
        self.closed = False
850
        def close():
851
            self.closed = True
852
        from_server.close = close
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
853
        server = medium.SmartServerPipeStreamMedium(
854
            to_server, from_server, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
855
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
856
        server._serve_one_request(fake_protocol)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
857
        self.assertEqual('', from_server.getvalue())
858
        self.assertTrue(self.closed)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
859
        self.assertTrue(server.finished)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
860
        
861
    def test_socket_stream_error_handling(self):
862
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
863
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
864
            server_sock, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
865
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
866
        server._serve_one_request(fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
867
        # recv should not block, because the other end of the socket has been
868
        # closed.
869
        self.assertEqual('', client_sock.recv(1))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
870
        self.assertTrue(server.finished)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
871
        
872
    def test_pipe_like_stream_keyboard_interrupt_handling(self):
873
        to_server = StringIO('')
874
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
875
        server = medium.SmartServerPipeStreamMedium(
876
            to_server, from_server, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
877
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
878
        self.assertRaises(
879
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
880
        self.assertEqual('', from_server.getvalue())
881
882
    def test_socket_stream_keyboard_interrupt_handling(self):
883
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
884
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
885
            server_sock, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
886
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
887
        self.assertRaises(
888
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
889
        server_sock.close()
890
        self.assertEqual('', client_sock.recv(1))
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
891
892
    def build_protocol_pipe_like(self, bytes):
893
        to_server = StringIO(bytes)
894
        from_server = StringIO()
895
        server = medium.SmartServerPipeStreamMedium(
896
            to_server, from_server, None)
897
        return server._build_protocol()
898
899
    def build_protocol_socket(self, bytes):
900
        server_sock, client_sock = self.portable_socket_pair()
901
        server = medium.SmartServerSocketStreamMedium(
902
            server_sock, None)
903
        client_sock.sendall(bytes)
904
        client_sock.close()
905
        return server._build_protocol()
906
907
    def assertProtocolOne(self, server_protocol):
908
        # Use assertIs because assertIsInstance will wrongly pass
909
        # SmartServerRequestProtocolTwo (because it subclasses
910
        # SmartServerRequestProtocolOne).
911
        self.assertIs(
912
            type(server_protocol), protocol.SmartServerRequestProtocolOne)
913
914
    def assertProtocolTwo(self, server_protocol):
915
        self.assertIsInstance(
916
            server_protocol, protocol.SmartServerRequestProtocolTwo)
917
918
    def test_pipe_like_build_protocol_empty_bytes(self):
919
        # Any empty request (i.e. no bytes) is detected as protocol version one.
920
        server_protocol = self.build_protocol_pipe_like('')
921
        self.assertProtocolOne(server_protocol)
922
        
923
    def test_socket_like_build_protocol_empty_bytes(self):
924
        # Any empty request (i.e. no bytes) is detected as protocol version one.
925
        server_protocol = self.build_protocol_socket('')
926
        self.assertProtocolOne(server_protocol)
927
928
    def test_pipe_like_build_protocol_non_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
929
        # A request that doesn't start with "bzr request 2\n" is version one.
930
        server_protocol = self.build_protocol_pipe_like('abc\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
931
        self.assertProtocolOne(server_protocol)
932
933
    def test_socket_build_protocol_non_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
934
        # A request that doesn't start with "bzr request 2\n" is version one.
935
        server_protocol = self.build_protocol_socket('abc\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
936
        self.assertProtocolOne(server_protocol)
937
938
    def test_pipe_like_build_protocol_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
939
        # A request that starts with "bzr request 2\n" is version two.
940
        server_protocol = self.build_protocol_pipe_like('bzr request 2\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
941
        self.assertProtocolTwo(server_protocol)
942
943
    def test_socket_build_protocol_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
944
        # A request that starts with "bzr request 2\n" is version two.
945
        server_protocol = self.build_protocol_socket('bzr request 2\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
946
        self.assertProtocolTwo(server_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
947
        
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
948
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
949
class TestSmartTCPServer(tests.TestCase):
950
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
951
    def test_get_error_unexpected(self):
952
        """Error reported by server with no specific representation"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
953
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
954
        class FlakyTransport(object):
2376.3.3 by Robert Collins
Fix all smart_transport tests.
955
            base = 'a_url'
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
956
            def external_url(self):
957
                return self.base
1910.19.14 by Robert Collins
Fix up all tests to pass, remove a couple more deprecated function calls, and break the dependency on sftp for the smart transport.
958
            def get_bytes(self, path):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
959
                raise Exception("some random exception from inside server")
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
960
        smart_server = server.SmartTCPServer(backing_transport=FlakyTransport())
961
        smart_server.start_background_thread()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
962
        try:
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
963
            transport = remote.RemoteTCPTransport(smart_server.get_url())
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
964
            try:
965
                transport.get('something')
966
            except errors.TransportError, e:
967
                self.assertContainsRe(str(e), 'some random exception')
968
            else:
969
                self.fail("get did not raise expected error")
2018.5.171 by Andrew Bennetts
Disconnect RemoteTransports in some tests to avoid tripping up test_strace with leftover threads from previous tests.
970
            transport.disconnect()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
971
        finally:
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
972
            smart_server.stop_background_thread()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
973
974
975
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
976
    """Tests for connection/end to end behaviour using the TCP server.
977
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
978
    All of these tests are run with a server running on another thread serving
979
    a MemoryTransport, and a connection to it already open.
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
980
981
    the server is obtained by calling self.setUpServer(readonly=False).
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
982
    """
983
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
984
    def setUpServer(self, readonly=False, backing_transport=None):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
985
        """Setup the server.
986
987
        :param readonly: Create a readonly server.
988
        """
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
989
        if not backing_transport:
990
            self.backing_transport = memory.MemoryTransport()
991
        else:
992
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
993
        if readonly:
994
            self.real_backing_transport = self.backing_transport
995
            self.backing_transport = get_transport("readonly+" + self.backing_transport.abspath('.'))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
996
        self.server = server.SmartTCPServer(self.backing_transport)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
997
        self.server.start_background_thread()
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
998
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
999
        self.addCleanup(self.tearDownServer)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1000
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1001
    def tearDownServer(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1002
        if getattr(self, 'transport', None):
1003
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1004
            del self.transport
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1005
        if getattr(self, 'server', None):
1006
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1007
            del self.server
1008
1009
1010
class TestServerSocketUsage(SmartTCPTests):
1011
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1012
    def test_server_setup_teardown(self):
1013
        """It should be safe to teardown the server with no requests."""
1014
        self.setUpServer()
1015
        server = self.server
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1016
        transport = remote.RemoteTCPTransport(self.server.get_url())
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1017
        self.tearDownServer()
1018
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1019
1020
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
1021
        """The server should close its listening socket when it's stopped."""
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1022
        self.setUpServer()
2370.4.2 by Robert Collins
Review feedback.
1023
        server = self.server
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1024
        self.transport.has('.')
1025
        self.tearDownServer()
1026
        # if the listening socket has closed, we should get a BADFD error
1027
        # when connecting, rather than a hang.
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1028
        transport = remote.RemoteTCPTransport(server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1029
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1030
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1031
1032
class WritableEndToEndTests(SmartTCPTests):
1033
    """Client to server tests that require a writable transport."""
1034
1035
    def setUp(self):
1036
        super(WritableEndToEndTests, self).setUp()
1037
        self.setUpServer()
1038
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1039
    def test_start_tcp_server(self):
1040
        url = self.server.get_url()
1041
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
1042
1043
    def test_smart_transport_has(self):
1044
        """Checking for file existence over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1045
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1046
        self.backing_transport.put_bytes("foo", "contents of foo\n")
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1047
        self.assertTrue(self.transport.has("foo"))
1048
        self.assertFalse(self.transport.has("non-foo"))
1049
1050
    def test_smart_transport_get(self):
1051
        """Read back a file over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1052
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1053
        self.backing_transport.put_bytes("foo", "contents\nof\nfoo\n")
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1054
        fp = self.transport.get("foo")
1055
        self.assertEqual('contents\nof\nfoo\n', fp.read())
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1056
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1057
    def test_get_error_enoent(self):
1058
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
1059
        # The path in a raised NoSuchFile exception should be the precise path
1060
        # asked for by the client. This gives meaningful and unsurprising errors
1061
        # for users.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1062
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1063
        try:
1752.2.80 by Andrew Bennetts
Some urlquoting fixes, a double-slash fix, a fix for an incorrect test (still failing though) and remove an apparently obsolete comment.
1064
            self.transport.get('not%20a%20file')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1065
        except errors.NoSuchFile, e:
1752.2.80 by Andrew Bennetts
Some urlquoting fixes, a double-slash fix, a fix for an incorrect test (still failing though) and remove an apparently obsolete comment.
1066
            self.assertEqual('not%20a%20file', e.path)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1067
        else:
1068
            self.fail("get did not raise expected error")
1069
1070
    def test_simple_clone_conn(self):
1071
        """Test that cloning reuses the same connection."""
1072
        # we create a real connection not a loopback one, but it will use the
1073
        # same server and pipes
1752.2.74 by Andrew Bennetts
Make SmartTransport.clone return the right class, and move connection sharing into clone from __init__.
1074
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1075
        self.assertIs(self.transport.get_smart_medium(),
1076
                      conn2.get_smart_medium())
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1077
1910.19.12 by Andrew Bennetts
Activate a disabled test, rename another test to be consistent with what it's testing. (Andrew Bennetts, Robert Collins)
1078
    def test__remote_path(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1079
        self.assertEquals('/foo/bar',
1080
                          self.transport._remote_path('foo/bar'))
1081
1082
    def test_clone_changes_base(self):
1083
        """Cloning transport produces one with a new base location"""
1084
        conn2 = self.transport.clone('subdir')
1085
        self.assertEquals(self.transport.base + 'subdir/',
1086
                          conn2.base)
1087
1088
    def test_open_dir(self):
1089
        """Test changing directory"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1090
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1091
        transport = self.transport
1092
        self.backing_transport.mkdir('toffee')
1093
        self.backing_transport.mkdir('toffee/apple')
1094
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1095
        toffee_trans = transport.clone('toffee')
1096
        # Check that each transport has only the contents of its directory
1097
        # directly visible. If state was being held in the wrong object, it's
1098
        # conceivable that cloning a transport would alter the state of the
1099
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1100
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1101
        self.assertFalse(toffee_trans.has('toffee'))
1102
        self.assertFalse(transport.has('apple'))
1103
        self.assertTrue(toffee_trans.has('apple'))
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1104
1105
    def test_open_bzrdir(self):
1106
        """Open an existing bzrdir over smart transport"""
1107
        transport = self.transport
1108
        t = self.backing_transport
1109
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
1110
        result_dir = bzrdir.BzrDir.open_containing_from_transport(transport)
1111
1112
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1113
class ReadOnlyEndToEndTests(SmartTCPTests):
1114
    """Tests from the client to the server using a readonly backing transport."""
1115
1116
    def test_mkdir_error_readonly(self):
1117
        """TransportNotPossible should be preserved from the backing transport."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1118
        self._captureVar('BZR_NO_SMART_VFS', None)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1119
        self.setUpServer(readonly=True)
1120
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1121
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1122
1123
1124
class TestServerHooks(SmartTCPTests):
1125
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1126
    def capture_server_call(self, backing_urls, public_url):
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1127
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1128
        self.hook_calls.append((backing_urls, public_url))
1129
1130
    def test_server_started_hook_memory(self):
1131
        """The server_started hook fires when the server is started."""
1132
        self.hook_calls = []
1133
        server.SmartTCPServer.hooks.install_hook('server_started',
1134
            self.capture_server_call)
1135
        self.setUpServer()
1136
        # at this point, the server will be starting a thread up.
1137
        # there is no indicator at the moment, so bodge it by doing a request.
1138
        self.transport.has('.')
1139
        # The default test server uses MemoryTransport and that has no external
1140
        # url:
1141
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1142
            self.hook_calls)
1143
1144
    def test_server_started_hook_file(self):
1145
        """The server_started hook fires when the server is started."""
1146
        self.hook_calls = []
1147
        server.SmartTCPServer.hooks.install_hook('server_started',
1148
            self.capture_server_call)
1149
        self.setUpServer(backing_transport=get_transport("."))
1150
        # at this point, the server will be starting a thread up.
1151
        # there is no indicator at the moment, so bodge it by doing a request.
1152
        self.transport.has('.')
1153
        # The default test server uses MemoryTransport and that has no external
1154
        # url:
1155
        self.assertEqual([([
1156
            self.backing_transport.base, self.backing_transport.external_url()],
1157
             self.transport.base)],
1158
            self.hook_calls)
1159
1160
    def test_server_stopped_hook_simple_memory(self):
1161
        """The server_stopped hook fires when the server is stopped."""
1162
        self.hook_calls = []
1163
        server.SmartTCPServer.hooks.install_hook('server_stopped',
1164
            self.capture_server_call)
1165
        self.setUpServer()
1166
        result = [([self.backing_transport.base], self.transport.base)]
1167
        # check the stopping message isn't emitted up front.
1168
        self.assertEqual([], self.hook_calls)
1169
        # nor after a single message
1170
        self.transport.has('.')
1171
        self.assertEqual([], self.hook_calls)
1172
        # clean up the server
1173
        self.tearDownServer()
1174
        # now it should have fired.
1175
        self.assertEqual(result, self.hook_calls)
1176
1177
    def test_server_stopped_hook_simple_file(self):
1178
        """The server_stopped hook fires when the server is stopped."""
1179
        self.hook_calls = []
1180
        server.SmartTCPServer.hooks.install_hook('server_stopped',
1181
            self.capture_server_call)
1182
        self.setUpServer(backing_transport=get_transport("."))
1183
        result = [(
1184
            [self.backing_transport.base, self.backing_transport.external_url()]
1185
            , self.transport.base)]
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1186
        # check the stopping message isn't emitted up front.
1187
        self.assertEqual([], self.hook_calls)
1188
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1189
        self.transport.has('.')
1190
        self.assertEqual([], self.hook_calls)
1191
        # clean up the server
1192
        self.tearDownServer()
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1193
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1194
        self.assertEqual(result, self.hook_calls)
1195
1196
# TODO: test that when the server suffers an exception that it calls the
1197
# server-stopped hook.
1198
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1199
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1200
class SmartServerCommandTests(tests.TestCaseWithTransport):
1201
    """Tests that call directly into the command objects, bypassing the network
1202
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1203
1204
    Note: these tests are rudimentary versions of the command object tests in
1205
    test_remote.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1206
    """
1207
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1208
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1209
        cmd = _mod_request.HelloRequest(None, '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1210
        response = cmd.execute()
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1211
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1212
        self.assertEqual(None, response.body)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1213
        
1214
    def test_get_bundle(self):
1215
        from bzrlib.bundle import serializer
1216
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1217
        self.build_tree_contents([('hello', 'hello world')])
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1218
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1219
        rev_id = wt.commit('add hello')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1220
        
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1221
        cmd = _mod_request.GetBundleRequest(self.get_transport(), '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1222
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1223
        bundle = serializer.read_bundle(StringIO(response.body))
1224
        self.assertEqual((), response.args)
1225
1226
1227
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1228
    """Test that call directly into the handler logic, bypassing the network."""
1229
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1230
    def setUp(self):
1231
        super(SmartServerRequestHandlerTests, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
1232
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1233
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1234
    def build_handler(self, transport):
1235
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1236
        return _mod_request.SmartServerRequestHandler(
1237
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1238
1239
    def test_construct_request_handler(self):
1240
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1241
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1242
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1243
        self.assertFalse(handler.finished_reading)
1244
1245
    def test_hello(self):
1246
        handler = self.build_handler(None)
1247
        handler.dispatch_command('hello', ())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1248
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1249
        self.assertEqual(None, handler.response.body)
1250
        
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1251
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1252
        # VFS handler classes will raise an error from "execute" if
1253
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1254
        handler = vfs.HasRequest(None, '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1255
        # set environment variable after construction to make sure it's
1256
        # examined.
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1257
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1258
        # has called _captureVar, so it will be restored to the right state
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1259
        # afterwards.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1260
        os.environ['BZR_NO_SMART_VFS'] = ''
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1261
        self.assertRaises(errors.DisabledMethod, handler.execute)
1262
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1263
    def test_readonly_exception_becomes_transport_not_possible(self):
1264
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1265
        handler = self.build_handler(self.get_readonly_transport())
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1266
        # send a mkdir for foo, with no explicit mode - should fail.
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1267
        handler.dispatch_command('mkdir', ('foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1268
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1269
        self.assertEqual(("ReadOnlyError", ), handler.response.args)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1270
        # XXX: TODO: test that other TransportNotPossible errors are
1271
        # presented as TransportNotPossible - not possible to do that
1272
        # until I figure out how to trigger that relatively cleanly via
1273
        # the api. RBC 20060918
1274
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1275
    def test_hello_has_finished_body_on_dispatch(self):
1276
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1277
        handler = self.build_handler(None)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1278
        handler.dispatch_command('hello', ())
1279
        self.assertTrue(handler.finished_reading)
1280
        self.assertNotEqual(None, handler.response)
1281
1282
    def test_put_bytes_non_atomic(self):
1283
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1284
        handler = self.build_handler(self.get_transport())
2018.2.36 by Andrew Bennetts
Don't UTF-8 decode paths in requests. They should be url-quoted (and thus
1285
        handler.dispatch_command('put_non_atomic', ('a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1286
        self.assertFalse(handler.finished_reading)
1287
        handler.accept_body('1234')
1288
        self.assertFalse(handler.finished_reading)
1289
        handler.accept_body('5678')
1290
        handler.end_of_body()
1291
        self.assertTrue(handler.finished_reading)
1292
        self.assertEqual(('ok', ), handler.response.args)
1293
        self.assertEqual(None, handler.response.body)
1294
        
1295
    def test_readv_accept_body(self):
1296
        """'readv' should set finished_reading after reading offsets."""
1297
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1298
        handler = self.build_handler(self.get_readonly_transport())
2018.2.36 by Andrew Bennetts
Don't UTF-8 decode paths in requests. They should be url-quoted (and thus
1299
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1300
        self.assertFalse(handler.finished_reading)
1301
        handler.accept_body('2,')
1302
        self.assertFalse(handler.finished_reading)
1303
        handler.accept_body('3')
1304
        handler.end_of_body()
1305
        self.assertTrue(handler.finished_reading)
1306
        self.assertEqual(('readv', ), handler.response.args)
1307
        # co - nte - nt of a-file is the file contents we are extracting from.
1308
        self.assertEqual('nte', handler.response.body)
1309
1310
    def test_readv_short_read_response_contents(self):
1311
        """'readv' when a short read occurs sets the response appropriately."""
1312
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1313
        handler = self.build_handler(self.get_readonly_transport())
2018.2.36 by Andrew Bennetts
Don't UTF-8 decode paths in requests. They should be url-quoted (and thus
1314
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1315
        # read beyond the end of the file.
1316
        handler.accept_body('100,1')
1317
        handler.end_of_body()
1318
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1319
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1320
            handler.response.args)
1321
        self.assertEqual(None, handler.response.body)
1322
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1323
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1324
class RemoteTransportRegistration(tests.TestCase):
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1325
1326
    def test_registration(self):
1327
        t = get_transport('bzr+ssh://example.com/path')
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1328
        self.assertIsInstance(t, remote.RemoteSSHTransport)
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1329
        self.assertEqual('example.com', t._host)
1330
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1331
    def test_bzr_https(self):
1332
        # https://bugs.launchpad.net/bzr/+bug/128456
1333
        t = get_transport('bzr+https://example.com/path')
1334
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1335
        self.assertStartsWith(
1336
            t._http_transport.base,
1337
            'https://')
1338
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1339
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1340
class TestRemoteTransport(tests.TestCase):
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1341
        
1342
    def test_use_connection_factory(self):
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1343
        # We want to be able to pass a client as a parameter to RemoteTransport.
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1344
        input = StringIO("ok\n3\nbardone\n")
1345
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1346
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1347
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1348
            'bzr://localhost/', medium=client_medium)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1349
1350
        # We want to make sure the client is used when the first remote
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1351
        # method is called.  No data should have been sent, or read.
1352
        self.assertEqual(0, input.tell())
1353
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1354
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1355
        # Now call a method that should result in a single request : as the
1356
        # transport makes its own protocol instances, we check on the wire.
1357
        # XXX: TODO: give the transport a protocol factory, which can make
1358
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1359
        self.assertEqual('bar', transport.get_bytes('foo'))
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1360
        # only the needed data should have been sent/received.
1361
        self.assertEqual(13, input.tell())
1362
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1363
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1364
    def test__translate_error_readonly(self):
1365
        """Sending a ReadOnlyError to _translate_error raises TransportNotPossible."""
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1366
        client_medium = medium.SmartClientMedium()
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1367
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1368
            'bzr://localhost/', medium=client_medium)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1369
        self.assertRaises(errors.TransportNotPossible,
1370
            transport._translate_error, ("ReadOnlyError", ))
1371
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1372
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1373
class TestSmartProtocol(tests.TestCase):
1374
    """Base class for smart protocol tests.
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1375
1376
    Each test case gets a smart_server and smart_client created during setUp().
1377
1378
    It is planned that the client can be called with self.call_client() giving
1379
    it an expected server response, which will be fed into it when it tries to
1380
    read. Likewise, self.call_server will call a servers method with a canned
1381
    serialised client request. Output done by the client or server for these
1382
    calls will be captured to self.to_server and self.to_client. Each element
1383
    in the list is a write call from the client or server respectively.
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1384
1385
    Subclasses can override client_protocol_class and server_protocol_class.
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1386
    """
1387
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1388
    client_protocol_class = None
1389
    server_protocol_class = None
1390
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1391
    def make_client_protocol(self):
3245.1.6 by Andrew Bennetts
Remove more cruft from TestSmartProtocol.setUp.
1392
        client_medium = medium.SmartSimplePipesClientMedium(
1393
            StringIO(), StringIO())
3245.1.9 by Andrew Bennetts
Use TestSmartProtocol.make_client_protocol in test_connection_closed_reporting.
1394
        return self.client_protocol_class(client_medium.get_request())
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1395
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1396
    def make_server_protocol(self):
1397
        out_stream = StringIO()
1398
        smart_protocol = self.server_protocol_class(None, out_stream.write)
1399
        return smart_protocol, out_stream
1400
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1401
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
1402
        client):
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1403
        """Check that smart (de)serialises offsets as expected.
1404
        
1405
        We check both serialisation and deserialisation at the same time
1406
        to ensure that the round tripping cannot skew: both directions should
1407
        be as expected.
1408
        
1409
        :param expected_offsets: a readv offset list.
1410
        :param expected_seralised: an expected serial form of the offsets.
1411
        """
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
1412
        # XXX: '_deserialise_offsets' should be a method of the
1413
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1414
        readv_cmd = vfs.ReadvRequest(None, '/')
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
1415
        offsets = readv_cmd._deserialise_offsets(expected_serialised)
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1416
        self.assertEqual(expected_offsets, offsets)
1417
        serialised = client._serialise_offsets(offsets)
1418
        self.assertEqual(expected_serialised, serialised)
1419
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1420
    def build_protocol_waiting_for_body(self):
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1421
        smart_protocol, out_stream = self.make_server_protocol()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1422
        smart_protocol.has_dispatched = True
3245.1.14 by Andrew Bennetts
Merge from bzr.dev
1423
        smart_protocol.request = _mod_request.SmartServerRequestHandler(
1424
            None, _mod_request.request_handlers, '/')
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1425
        class FakeCommand(object):
1426
            def do_body(cmd, body_bytes):
1427
                self.end_received = True
1428
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1429
                return _mod_request.SuccessfulSmartServerResponse(('ok', ))
2018.5.12 by Andrew Bennetts
Rename SmartServerRequestHandler's command attribute to _command; it's private.
1430
        smart_protocol.request._command = FakeCommand()
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1431
        # Call accept_bytes to make sure that internal state like _body_decoder
1432
        # is initialised.  This test should probably be given a clearer
1433
        # interface to work with that will not cause this inconsistency.
1434
        #   -- Andrew Bennetts, 2006-09-28
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1435
        smart_protocol.accept_bytes('')
1436
        return smart_protocol
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1437
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1438
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
1439
            input_tuples):
1440
        """Assert that each input_tuple serialises as expected_bytes, and the
1441
        bytes deserialise as expected_tuple.
1442
        """
1443
        # check the encoding of the server for all input_tuples matches
1444
        # expected bytes
1445
        for input_tuple in input_tuples:
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1446
            server_protocol, server_output = self.make_server_protocol()
2432.4.4 by Robert Collins
Merge hpss-protocol2.
1447
            server_protocol._send_response(
1448
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1449
            self.assertEqual(expected_bytes, server_output.getvalue())
1450
        # check the decoding of the client smart_protocol from expected_bytes:
1451
        input = StringIO(expected_bytes)
1452
        output = StringIO()
1453
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1454
        request = client_medium.get_request()
1455
        smart_protocol = self.client_protocol_class(request)
1456
        smart_protocol.call('foo')
1457
        self.assertEqual(expected_tuple, smart_protocol.read_response_tuple())
1458
1459
2621.3.1 by Andrew Bennetts
Log errors from the smart server in the trace file, to make debugging test failures (and live failures!) easier.
1460
class CommonSmartProtocolTestMixin(object):
1461
1462
    def test_errors_are_logged(self):
1463
        """If an error occurs during testing, it is logged to the test log."""
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1464
        smart_protocol, out_stream = self.make_server_protocol()
2621.3.1 by Andrew Bennetts
Log errors from the smart server in the trace file, to make debugging test failures (and live failures!) easier.
1465
        # This triggers a "bad request" error.
1466
        smart_protocol.accept_bytes('abc\n')
1467
        test_log = self._get_log(keep_log_file=True)
1468
        self.assertContainsRe(test_log, 'Traceback')
1469
        self.assertContainsRe(test_log, 'SmartProtocolError')
1470
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1471
    def test_connection_closed_reporting(self):
3245.1.9 by Andrew Bennetts
Use TestSmartProtocol.make_client_protocol in test_connection_closed_reporting.
1472
        smart_protocol = self.make_client_protocol()
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1473
        smart_protocol.call('hello')
3245.1.10 by Andrew Bennetts
Remove trailing whitespace.
1474
        ex = self.assertRaises(errors.ConnectionReset,
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1475
            smart_protocol.read_response_tuple)
1476
        self.assertEqual("Connection closed: "
1477
            "please check connectivity and permissions "
1478
            "(and try -Dhpss if further diagnosis is required)", str(ex))
1479
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1480
    def test_server_offset_serialisation(self):
1481
        """The Smart protocol serialises offsets as a comma and \n string.
1482
1483
        We check a number of boundary cases are as expected: empty, one offset,
1484
        one with the order of reads not increasing (an out of order read), and
1485
        one that should coalesce.
1486
        """
1487
        client_protocol = self.make_client_protocol()
1488
        self.assertOffsetSerialisation([], '', client_protocol)
1489
        self.assertOffsetSerialisation([(1,2)], '1,2', client_protocol)
1490
        self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
1491
            client_protocol)
1492
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1493
            '1,2\n3,4\n100,200', client_protocol)
1494
2621.3.1 by Andrew Bennetts
Log errors from the smart server in the trace file, to make debugging test failures (and live failures!) easier.
1495
1496
class TestSmartProtocolOne(TestSmartProtocol, CommonSmartProtocolTestMixin):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1497
    """Tests for the smart protocol version one."""
1498
1499
    client_protocol_class = protocol.SmartClientRequestProtocolOne
1500
    server_protocol_class = protocol.SmartServerRequestProtocolOne
1501
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1502
    def test_construct_version_one_server_protocol(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1503
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
1504
        self.assertEqual('', smart_protocol.excess_buffer)
1505
        self.assertEqual('', smart_protocol.in_buffer)
1506
        self.assertFalse(smart_protocol.has_dispatched)
1507
        self.assertEqual(1, smart_protocol.next_read_size())
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1508
1509
    def test_construct_version_one_client_protocol(self):
1510
        # we can construct a client protocol from a client medium request
1511
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1512
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
1513
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1514
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1515
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1516
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1517
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1518
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1519
            None, out_stream.write)
1520
        smart_protocol.accept_bytes('abc')
1521
        self.assertEqual('abc', smart_protocol.in_buffer)
1522
        smart_protocol.accept_bytes('\n')
1523
        self.assertEqual(
1524
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
1525
            out_stream.getvalue())
1526
        self.assertTrue(smart_protocol.has_dispatched)
1527
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
1528
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1529
    def test_accept_body_bytes_to_protocol(self):
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1530
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1531
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1532
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1533
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1534
        protocol.accept_bytes('defgd')
1535
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1536
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1537
        self.assertTrue(self.end_received)
1538
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1539
    def test_accept_request_and_body_all_at_once(self):
2402.1.2 by Andrew Bennetts
Deal with review comments.
1540
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1541
        mem_transport = memory.MemoryTransport()
1542
        mem_transport.put_bytes('foo', 'abcdefghij')
1543
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1544
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
1545
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1546
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1547
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1548
        self.assertEqual('readv\n3\ndefdone\n', out_stream.getvalue())
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1549
        self.assertEqual('', smart_protocol.excess_buffer)
1550
        self.assertEqual('', smart_protocol.in_buffer)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1551
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1552
    def test_accept_excess_bytes_are_preserved(self):
1553
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1554
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1555
            None, out_stream.write)
1556
        smart_protocol.accept_bytes('hello\nhello\n')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1557
        self.assertEqual("ok\x012\n", out_stream.getvalue())
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1558
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1559
        self.assertEqual("", smart_protocol.in_buffer)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1560
1561
    def test_accept_excess_bytes_after_body(self):
1562
        protocol = self.build_protocol_waiting_for_body()
1563
        protocol.accept_bytes('7\nabcdefgdone\nX')
1564
        self.assertTrue(self.end_received)
1565
        self.assertEqual("X", protocol.excess_buffer)
1566
        self.assertEqual("", protocol.in_buffer)
1567
        protocol.accept_bytes('Y')
1568
        self.assertEqual("XY", protocol.excess_buffer)
1569
        self.assertEqual("", protocol.in_buffer)
1570
1571
    def test_accept_excess_bytes_after_dispatch(self):
1572
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1573
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1574
            None, out_stream.write)
1575
        smart_protocol.accept_bytes('hello\n')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1576
        self.assertEqual("ok\x012\n", out_stream.getvalue())
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1577
        smart_protocol.accept_bytes('hel')
1578
        self.assertEqual("hel", smart_protocol.excess_buffer)
1579
        smart_protocol.accept_bytes('lo\n')
1580
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1581
        self.assertEqual("", smart_protocol.in_buffer)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1582
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1583
    def test__send_response_sets_finished_reading(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1584
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1585
            None, lambda x: None)
1586
        self.assertEqual(1, smart_protocol.next_read_size())
2432.4.3 by Robert Collins
Refactor the HPSS Response code to take SmartServerResponse rather than args and body.
1587
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1588
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1589
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1590
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1591
    def test__send_response_errors_with_base_response(self):
1592
        """Ensure that only the Successful/Failed subclasses are used."""
1593
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1594
            None, lambda x: None)
1595
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1596
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1597
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1598
    def test_query_version(self):
1599
        """query_version on a SmartClientProtocolOne should return a number.
1600
        
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1601
        The protocol provides the query_version because the domain level clients
1602
        may all need to be able to probe for capabilities.
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1603
        """
1604
        # What we really want to test here is that SmartClientProtocolOne calls
1605
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1606
        # response of tuple-encoded (ok, 1).  Also, seperately we should test
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1607
        # the error if the response is a non-understood version.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1608
        input = StringIO('ok\x012\n')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1609
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1610
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1611
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1612
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1613
        self.assertEqual(2, smart_protocol.query_version())
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1614
1615
    def test_client_call_empty_response(self):
1616
        # protocol.call() can get back an empty tuple as a response. This occurs
1617
        # when the parsed line is an empty line, and results in a tuple with
1618
        # one element - an empty string.
1619
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
1620
1621
    def test_client_call_three_element_response(self):
1622
        # protocol.call() can get back tuples of other lengths. A three element
1623
        # tuple should be unpacked as three strings.
1624
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
1625
            [('a', 'b', '34')])
1626
1627
    def test_client_call_with_body_bytes_uploads(self):
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
1628
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1629
        # wire.
1630
        expected_bytes = "foo\n7\nabcdefgdone\n"
1631
        input = StringIO("\n")
1632
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1633
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1634
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1635
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1636
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1637
        self.assertEqual(expected_bytes, output.getvalue())
1638
1639
    def test_client_call_with_body_readv_array(self):
1640
        # protocol.call_with_upload should encode the readv array and then
1641
        # length-prefix the bytes onto the wire.
1642
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
1643
        input = StringIO("\n")
1644
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1645
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1646
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1647
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1648
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1649
        self.assertEqual(expected_bytes, output.getvalue())
1650
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
1651
    def _test_client_read_response_tuple_raises_UnknownSmartMethod(self,
1652
            server_bytes):
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1653
        input = StringIO(server_bytes)
1654
        output = StringIO()
1655
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1656
        request = client_medium.get_request()
1657
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1658
        smart_protocol.call('foo')
1659
        self.assertRaises(
1660
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
1661
        # The request has been finished.  There is no body to read, and
1662
        # attempts to read one will fail.
1663
        self.assertRaises(
1664
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1665
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
1666
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
1667
        """read_response_tuple raises UnknownSmartMethod if the response says
1668
        the server did not recognise the request.
1669
        """
1670
        server_bytes = (
1671
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
1672
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1673
            server_bytes)
1674
1675
    def test_client_read_response_tuple_raises_UnknownSmartMethod_0_11(self):
1676
        """read_response_tuple also raises UnknownSmartMethod if the response
1677
        from a bzr 0.11 says the server did not recognise the request.
1678
1679
        (bzr 0.11 sends a slightly different error message to later versions.)
1680
        """
1681
        server_bytes = (
1682
            "error\x01Generic bzr smart protocol error: bad request u'foo'\n")
1683
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1684
            server_bytes)
1685
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1686
    def test_client_read_body_bytes_all(self):
1687
        # read_body_bytes should decode the body bytes from the wire into
1688
        # a response.
1689
        expected_bytes = "1234567"
1690
        server_bytes = "ok\n7\n1234567done\n"
1691
        input = StringIO(server_bytes)
1692
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1693
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1694
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1695
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1696
        smart_protocol.call('foo')
1697
        smart_protocol.read_response_tuple(True)
1698
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1699
1700
    def test_client_read_body_bytes_incremental(self):
1701
        # test reading a few bytes at a time from the body
1702
        # XXX: possibly we should test dribbling the bytes into the stringio
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1703
        # to make the state machine work harder: however, as we use the
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1704
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1705
        # that.
1706
        expected_bytes = "1234567"
1707
        server_bytes = "ok\n7\n1234567done\n"
1708
        input = StringIO(server_bytes)
1709
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1710
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1711
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1712
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1713
        smart_protocol.call('foo')
1714
        smart_protocol.read_response_tuple(True)
1715
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1716
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1717
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1718
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1719
1720
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1721
        # cancelling the expected body needs to finish the request, but not
1722
        # read any more bytes.
1723
        expected_bytes = "1234567"
1724
        server_bytes = "ok\n7\n1234567done\n"
1725
        input = StringIO(server_bytes)
1726
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1727
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1728
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1729
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1730
        smart_protocol.call('foo')
1731
        smart_protocol.read_response_tuple(True)
1732
        smart_protocol.cancel_read_body()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1733
        self.assertEqual(3, input.tell())
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1734
        self.assertRaises(
1735
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1736
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1737
2621.3.1 by Andrew Bennetts
Log errors from the smart server in the trace file, to make debugging test failures (and live failures!) easier.
1738
class TestSmartProtocolTwo(TestSmartProtocol, CommonSmartProtocolTestMixin):
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1739
    """Tests for the smart protocol version two.
1740
1741
    This test case is mostly the same as TestSmartProtocolOne.
1742
    """
1743
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1744
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
1745
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1746
1747
    def test_construct_version_two_server_protocol(self):
1748
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
1749
        self.assertEqual('', smart_protocol.excess_buffer)
1750
        self.assertEqual('', smart_protocol.in_buffer)
1751
        self.assertFalse(smart_protocol.has_dispatched)
1752
        self.assertEqual(1, smart_protocol.next_read_size())
1753
1754
    def test_construct_version_two_client_protocol(self):
1755
        # we can construct a client protocol from a client medium request
1756
        output = StringIO()
1757
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
1758
        request = client_medium.get_request()
1759
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1760
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1761
    def assertBodyStreamSerialisation(self, expected_serialisation,
1762
                                      body_stream):
1763
        """Assert that body_stream is serialised as expected_serialisation."""
1764
        out_stream = StringIO()
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1765
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
1766
        self.assertEqual(expected_serialisation, out_stream.getvalue())
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1767
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1768
    def assertBodyStreamRoundTrips(self, body_stream):
1769
        """Assert that body_stream is the same after being serialised and
1770
        deserialised.
1771
        """
1772
        out_stream = StringIO()
1773
        protocol._send_stream(body_stream, out_stream.write)
1774
        decoder = protocol.ChunkedBodyDecoder()
1775
        decoder.accept_bytes(out_stream.getvalue())
1776
        decoded_stream = list(iter(decoder.read_next_chunk, None))
1777
        self.assertEqual(body_stream, decoded_stream)
1778
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1779
    def test_body_stream_serialisation_empty(self):
1780
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1781
        self.assertBodyStreamSerialisation('chunked\nEND\n', [])
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1782
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1783
1784
    def test_body_stream_serialisation(self):
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1785
        stream = ['chunk one', 'chunk two', 'chunk three']
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1786
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1787
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
1788
            'END\n',
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1789
            stream)
1790
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1791
1792
    def test_body_stream_with_empty_element_serialisation(self):
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
1793
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1794
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
1795
        The empty string can be transmitted like any other string.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1796
        """
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1797
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
1798
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1799
            'chunked\n' + '0\n' + '5\nchunk' + 'END\n', stream)
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1800
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1801
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1802
    def test_body_stream_error_serialistion(self):
1803
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
1804
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1805
                      ('FailureName', 'failure arg'))]
1806
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1807
            'chunked\n' + 'b\nfirst chunk' +
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1808
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
1809
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1810
        self.assertBodyStreamSerialisation(expected_bytes, stream)
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
1811
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1812
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1813
    def test_accept_bytes_of_bad_request_to_protocol(self):
1814
        out_stream = StringIO()
1815
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1816
            None, out_stream.write)
1817
        smart_protocol.accept_bytes('abc')
1818
        self.assertEqual('abc', smart_protocol.in_buffer)
1819
        smart_protocol.accept_bytes('\n')
1820
        self.assertEqual(
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1821
            protocol.RESPONSE_VERSION_TWO +
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1822
            "failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1823
            out_stream.getvalue())
1824
        self.assertTrue(smart_protocol.has_dispatched)
1825
        self.assertEqual(0, smart_protocol.next_read_size())
1826
1827
    def test_accept_body_bytes_to_protocol(self):
1828
        protocol = self.build_protocol_waiting_for_body()
1829
        self.assertEqual(6, protocol.next_read_size())
1830
        protocol.accept_bytes('7\nabc')
1831
        self.assertEqual(9, protocol.next_read_size())
1832
        protocol.accept_bytes('defgd')
1833
        protocol.accept_bytes('one\n')
1834
        self.assertEqual(0, protocol.next_read_size())
1835
        self.assertTrue(self.end_received)
1836
1837
    def test_accept_request_and_body_all_at_once(self):
1838
        self._captureVar('BZR_NO_SMART_VFS', None)
1839
        mem_transport = memory.MemoryTransport()
1840
        mem_transport.put_bytes('foo', 'abcdefghij')
1841
        out_stream = StringIO()
1842
        smart_protocol = protocol.SmartServerRequestProtocolTwo(mem_transport,
1843
                out_stream.write)
1844
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1845
        self.assertEqual(0, smart_protocol.next_read_size())
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1846
        self.assertEqual(protocol.RESPONSE_VERSION_TWO +
1847
                         'success\nreadv\n3\ndefdone\n',
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1848
                         out_stream.getvalue())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1849
        self.assertEqual('', smart_protocol.excess_buffer)
1850
        self.assertEqual('', smart_protocol.in_buffer)
1851
1852
    def test_accept_excess_bytes_are_preserved(self):
1853
        out_stream = StringIO()
1854
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1855
            None, out_stream.write)
1856
        smart_protocol.accept_bytes('hello\nhello\n')
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1857
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + "success\nok\x012\n",
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1858
                         out_stream.getvalue())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1859
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1860
        self.assertEqual("", smart_protocol.in_buffer)
1861
1862
    def test_accept_excess_bytes_after_body(self):
1863
        # The excess bytes look like the start of another request.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1864
        server_protocol = self.build_protocol_waiting_for_body()
1865
        server_protocol.accept_bytes(
1866
            '7\nabcdefgdone\n' + protocol.RESPONSE_VERSION_TWO)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1867
        self.assertTrue(self.end_received)
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1868
        self.assertEqual(protocol.RESPONSE_VERSION_TWO,
1869
                         server_protocol.excess_buffer)
1870
        self.assertEqual("", server_protocol.in_buffer)
1871
        server_protocol.accept_bytes('Y')
1872
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + "Y",
1873
                         server_protocol.excess_buffer)
1874
        self.assertEqual("", server_protocol.in_buffer)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1875
1876
    def test_accept_excess_bytes_after_dispatch(self):
1877
        out_stream = StringIO()
1878
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1879
            None, out_stream.write)
1880
        smart_protocol.accept_bytes('hello\n')
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1881
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + "success\nok\x012\n",
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1882
                         out_stream.getvalue())
1883
        smart_protocol.accept_bytes(protocol.REQUEST_VERSION_TWO + 'hel')
1884
        self.assertEqual(protocol.REQUEST_VERSION_TWO + "hel",
1885
                         smart_protocol.excess_buffer)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1886
        smart_protocol.accept_bytes('lo\n')
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1887
        self.assertEqual(protocol.REQUEST_VERSION_TWO + "hello\n",
1888
                         smart_protocol.excess_buffer)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1889
        self.assertEqual("", smart_protocol.in_buffer)
1890
1891
    def test__send_response_sets_finished_reading(self):
1892
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1893
            None, lambda x: None)
1894
        self.assertEqual(1, smart_protocol.next_read_size())
2432.4.3 by Robert Collins
Refactor the HPSS Response code to take SmartServerResponse rather than args and body.
1895
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1896
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1897
        self.assertEqual(0, smart_protocol.next_read_size())
1898
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1899
    def test__send_response_with_body_stream_sets_finished_reading(self):
1900
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1901
            None, lambda x: None)
1902
        self.assertEqual(1, smart_protocol.next_read_size())
1903
        smart_protocol._send_response(
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
1904
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1905
        self.assertEqual(0, smart_protocol.next_read_size())
1906
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1907
    def test__send_response_errors_with_base_response(self):
1908
        """Ensure that only the Successful/Failed subclasses are used."""
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1909
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1910
            None, lambda x: None)
1911
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1912
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1913
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1914
    def test__send_response_includes_failure_marker(self):
1915
        """FailedSmartServerResponse have 'failed\n' after the version."""
1916
        out_stream = StringIO()
1917
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1918
            None, out_stream.write)
1919
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1920
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
1921
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
1922
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1923
1924
    def test__send_response_includes_success_marker(self):
1925
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
1926
        out_stream = StringIO()
1927
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1928
            None, out_stream.write)
1929
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1930
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
1931
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
1932
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1933
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1934
    def test_query_version(self):
1935
        """query_version on a SmartClientProtocolTwo should return a number.
1936
        
1937
        The protocol provides the query_version because the domain level clients
1938
        may all need to be able to probe for capabilities.
1939
        """
1940
        # What we really want to test here is that SmartClientProtocolTwo calls
1941
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1942
        # response of tuple-encoded (ok, 1).  Also, seperately we should test
1943
        # the error if the response is a non-understood version.
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1944
        input = StringIO(protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1945
        output = StringIO()
1946
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1947
        request = client_medium.get_request()
1948
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1949
        self.assertEqual(2, smart_protocol.query_version())
1950
1951
    def test_client_call_empty_response(self):
1952
        # protocol.call() can get back an empty tuple as a response. This occurs
1953
        # when the parsed line is an empty line, and results in a tuple with
1954
        # one element - an empty string.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1955
        self.assertServerToClientEncoding(
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1956
            protocol.RESPONSE_VERSION_TWO + 'success\n\n', ('', ), [(), ('', )])
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1957
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1958
    def test_client_call_three_element_response(self):
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1959
        # protocol.call() can get back tuples of other lengths. A three element
1960
        # tuple should be unpacked as three strings.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1961
        self.assertServerToClientEncoding(
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1962
            protocol.RESPONSE_VERSION_TWO + 'success\na\x01b\x0134\n',
1963
            ('a', 'b', '34'),
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1964
            [('a', 'b', '34')])
1965
1966
    def test_client_call_with_body_bytes_uploads(self):
1967
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
1968
        # wire.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1969
        expected_bytes = protocol.REQUEST_VERSION_TWO + "foo\n7\nabcdefgdone\n"
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1970
        input = StringIO("\n")
1971
        output = StringIO()
1972
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1973
        request = client_medium.get_request()
1974
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1975
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1976
        self.assertEqual(expected_bytes, output.getvalue())
1977
1978
    def test_client_call_with_body_readv_array(self):
1979
        # protocol.call_with_upload should encode the readv array and then
1980
        # length-prefix the bytes onto the wire.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1981
        expected_bytes = protocol.REQUEST_VERSION_TWO+"foo\n7\n1,2\n5,6done\n"
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1982
        input = StringIO("\n")
1983
        output = StringIO()
1984
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1985
        request = client_medium.get_request()
1986
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1987
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1988
        self.assertEqual(expected_bytes, output.getvalue())
1989
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1990
    def test_client_read_response_tuple_sets_response_status(self):
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
1991
        server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1992
        input = StringIO(server_bytes)
1993
        output = StringIO()
1994
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1995
        request = client_medium.get_request()
1996
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1997
        smart_protocol.call('foo')
1998
        smart_protocol.read_response_tuple(False)
1999
        self.assertEqual(True, smart_protocol.response_status)
2000
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
2001
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2002
        """read_response_tuple raises UnknownSmartMethod if the response is
2003
        says the server did not recognise the request.
2004
        """
2005
        server_bytes = (
2006
            protocol.RESPONSE_VERSION_TWO +
2007
            "failed\n" +
2008
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2009
        input = StringIO(server_bytes)
2010
        output = StringIO()
2011
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2012
        request = client_medium.get_request()
2013
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2014
        smart_protocol.call('foo')
2015
        self.assertRaises(
2016
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2017
        self.assertEqual(False, smart_protocol.response_status)
2018
        # The request has been finished.  There is no body to read, and
2019
        # attempts to read one will fail.
2020
        self.assertRaises(
2021
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2022
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2023
    def test_client_read_body_bytes_all(self):
2024
        # read_body_bytes should decode the body bytes from the wire into
2025
        # a response.
2026
        expected_bytes = "1234567"
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
2027
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2028
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2029
        input = StringIO(server_bytes)
2030
        output = StringIO()
2031
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2032
        request = client_medium.get_request()
2033
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2034
        smart_protocol.call('foo')
2035
        smart_protocol.read_response_tuple(True)
2036
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
2037
2038
    def test_client_read_body_bytes_incremental(self):
2039
        # test reading a few bytes at a time from the body
2040
        # XXX: possibly we should test dribbling the bytes into the stringio
2041
        # to make the state machine work harder: however, as we use the
2042
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
2043
        # that.
2044
        expected_bytes = "1234567"
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
2045
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2046
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2047
        input = StringIO(server_bytes)
2048
        output = StringIO()
2049
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2050
        request = client_medium.get_request()
2051
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2052
        smart_protocol.call('foo')
2053
        smart_protocol.read_response_tuple(True)
2054
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2055
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2056
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2057
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2058
2059
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2060
        # cancelling the expected body needs to finish the request, but not
2061
        # read any more bytes.
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
2062
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2063
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2064
        input = StringIO(server_bytes)
2065
        output = StringIO()
2066
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2067
        request = client_medium.get_request()
2068
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2069
        smart_protocol.call('foo')
2070
        smart_protocol.read_response_tuple(True)
2071
        smart_protocol.cancel_read_body()
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
2072
        self.assertEqual(len(protocol.RESPONSE_VERSION_TWO + 'success\nok\n'),
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
2073
                         input.tell())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2074
        self.assertRaises(
2075
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2076
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2077
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2078
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2079
        two_body_chunks = "4\n1234" + "3\n567"
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2080
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2081
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2082
                        "success\nok\n" + body_header + two_body_chunks +
2083
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2084
        input = StringIO(server_bytes)
2085
        output = StringIO()
2086
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2087
        request = client_medium.get_request()
2088
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2089
        smart_protocol.call('foo')
2090
        smart_protocol.read_response_tuple(True)
2091
        stream = smart_protocol.read_streamed_body()
2092
        self.assertEqual(['1234', '567'], list(stream))
2093
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2094
    def test_read_streamed_body_error(self):
2095
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2096
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2097
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2098
        err_signal = 'ERR\n'
2099
        err_chunks = 'a\nerror arg1' + '4\narg2'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2100
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2101
        body = body_header + a_body_chunk + err_signal + err_chunks + finish
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2102
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2103
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2104
        input = StringIO(server_bytes)
2105
        output = StringIO()
2106
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2107
        smart_request = client_medium.get_request()
2108
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2109
        smart_protocol.call('foo')
2110
        smart_protocol.read_response_tuple(True)
2111
        expected_chunks = [
2112
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2113
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2114
        stream = smart_protocol.read_streamed_body()
2115
        self.assertEqual(expected_chunks, list(stream))
2116
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2117
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
2118
class TestSmartClientUnicode(tests.TestCase):
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2119
    """_SmartClient tests for unicode arguments.
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
2120
2121
    Unicode arguments to call_with_body_bytes are not correct (remote method
2122
    names, arguments, and bodies must all be expressed as byte strings), but
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2123
    _SmartClient should gracefully reject them, rather than getting into a
2124
    broken state that prevents future correct calls from working.  That is, it
2125
    should be possible to issue more requests on the medium afterwards, rather
2126
    than allowing one bad call to call_with_body_bytes to cause later calls to
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
2127
    mysteriously fail with TooManyConcurrentRequests.
2128
    """
2129
2130
    def assertCallDoesNotBreakMedium(self, method, args, body):
2131
        """Call a medium with the given method, args and body, then assert that
2132
        the medium is left in a sane state, i.e. is capable of allowing further
2133
        requests.
2134
        """
2135
        input = StringIO("\n")
2136
        output = StringIO()
2137
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
2138
        smart_client = client._SmartClient(client_medium, 'ignored base')
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
2139
        self.assertRaises(TypeError,
2140
            smart_client.call_with_body_bytes, method, args, body)
2141
        self.assertEqual("", output.getvalue())
2142
        self.assertEqual(None, client_medium._current_request)
2143
2144
    def test_call_with_body_bytes_unicode_method(self):
2145
        self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
2146
2147
    def test_call_with_body_bytes_unicode_args(self):
2148
        self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
2414.1.2 by Andrew Bennetts
Deal with review comments.
2149
        self.assertCallDoesNotBreakMedium('method', ('arg1', u'arg2'), 'body')
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
2150
2151
    def test_call_with_body_bytes_unicode_body(self):
2152
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
2153
2154
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2155
class LengthPrefixedBodyDecoder(tests.TestCase):
2156
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2157
    # XXX: TODO: make accept_reading_trailer invoke translate_response or 
2158
    # something similar to the ProtocolBase method.
2159
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2160
    def test_construct(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2161
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2162
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2163
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2164
        self.assertEqual('', decoder.read_pending_data())
2165
        self.assertEqual('', decoder.unused_data)
2166
2167
    def test_accept_bytes(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2168
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2169
        decoder.accept_bytes('')
2170
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2171
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2172
        self.assertEqual('', decoder.read_pending_data())
2173
        self.assertEqual('', decoder.unused_data)
2174
        decoder.accept_bytes('7')
2175
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2176
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2177
        self.assertEqual('', decoder.read_pending_data())
2178
        self.assertEqual('', decoder.unused_data)
2179
        decoder.accept_bytes('\na')
2180
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2181
        self.assertEqual(11, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2182
        self.assertEqual('a', decoder.read_pending_data())
2183
        self.assertEqual('', decoder.unused_data)
2184
        decoder.accept_bytes('bcdefgd')
2185
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2186
        self.assertEqual(4, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2187
        self.assertEqual('bcdefg', decoder.read_pending_data())
2188
        self.assertEqual('', decoder.unused_data)
2189
        decoder.accept_bytes('one')
2190
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2191
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2192
        self.assertEqual('', decoder.read_pending_data())
2193
        self.assertEqual('', decoder.unused_data)
2194
        decoder.accept_bytes('\nblarg')
2195
        self.assertTrue(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2196
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2197
        self.assertEqual('', decoder.read_pending_data())
2198
        self.assertEqual('blarg', decoder.unused_data)
2199
        
2200
    def test_accept_bytes_all_at_once_with_excess(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2201
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2202
        decoder.accept_bytes('1\nadone\nunused')
2203
        self.assertTrue(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2204
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2205
        self.assertEqual('a', decoder.read_pending_data())
2206
        self.assertEqual('unused', decoder.unused_data)
2207
2208
    def test_accept_bytes_exact_end_of_body(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2209
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2210
        decoder.accept_bytes('1\na')
2211
        self.assertFalse(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2212
        self.assertEqual(5, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2213
        self.assertEqual('a', decoder.read_pending_data())
2214
        self.assertEqual('', decoder.unused_data)
2215
        decoder.accept_bytes('done\n')
2216
        self.assertTrue(decoder.finished_reading)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2217
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2218
        self.assertEqual('', decoder.read_pending_data())
2219
        self.assertEqual('', decoder.unused_data)
2220
2221
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2222
class TestChunkedBodyDecoder(tests.TestCase):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2223
    """Tests for ChunkedBodyDecoder.
2224
    
2225
    This is the body decoder used for protocol version two.
2226
    """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2227
2228
    def test_construct(self):
2229
        decoder = protocol.ChunkedBodyDecoder()
2230
        self.assertFalse(decoder.finished_reading)
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2231
        self.assertEqual(8, decoder.next_read_size())
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2232
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2233
        self.assertEqual('', decoder.unused_data)
2234
2235
    def test_empty_content(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2236
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
2237
        """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2238
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2239
        decoder.accept_bytes('chunked\n')
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2240
        decoder.accept_bytes('END\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2241
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2242
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2243
        self.assertEqual('', decoder.unused_data)
2244
2245
    def test_one_chunk(self):
2246
        """A body in a single chunk is decoded correctly."""
2247
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2248
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2249
        chunk_length = 'f\n'
2250
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2251
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2252
        decoder.accept_bytes(chunk_length + chunk_content + finish)
2253
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2254
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2255
        self.assertEqual('', decoder.unused_data)
2256
        
2257
    def test_incomplete_chunk(self):
2258
        """When there are less bytes in the chunk than declared by the length,
2259
        then we haven't finished reading yet.
2260
        """
2261
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2262
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2263
        chunk_length = '8\n'
2264
        three_bytes = '123'
2265
        decoder.accept_bytes(chunk_length + three_bytes)
2266
        self.assertFalse(decoder.finished_reading)
2267
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2268
            5 + 4, decoder.next_read_size(),
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2269
            "The next_read_size hint should be the number of missing bytes in "
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2270
            "this chunk plus 4 (the length of the end-of-body marker: "
2271
            "'END\\n')")
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2272
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2273
2274
    def test_incomplete_length(self):
2275
        """A chunk length hasn't been read until a newline byte has been read.
2276
        """
2277
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2278
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2279
        decoder.accept_bytes('9')
2280
        self.assertEqual(
2281
            1, decoder.next_read_size(),
2282
            "The next_read_size hint should be 1, because we don't know the "
2283
            "length yet.")
2284
        decoder.accept_bytes('\n')
2285
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2286
            9 + 4, decoder.next_read_size(),
2287
            "The next_read_size hint should be the length of the chunk plus 4 "
2288
            "(the length of the end-of-body marker: 'END\\n')")
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2289
        self.assertFalse(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2290
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2291
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2292
    def test_two_chunks(self):
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2293
        """Content from multiple chunks is concatenated."""
2294
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2295
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2296
        chunk_one = '3\naaa'
2297
        chunk_two = '5\nbbbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2298
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2299
        decoder.accept_bytes(chunk_one + chunk_two + finish)
2300
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2301
        self.assertEqual('aaa', decoder.read_next_chunk())
2302
        self.assertEqual('bbbbb', decoder.read_next_chunk())
2303
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2304
        self.assertEqual('', decoder.unused_data)
2305
2306
    def test_excess_bytes(self):
2307
        """Bytes after the chunked body are reported as unused bytes."""
2308
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2309
        decoder.accept_bytes('chunked\n')
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2310
        chunked_body = "5\naaaaaEND\n"
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2311
        excess_bytes = "excess bytes"
2312
        decoder.accept_bytes(chunked_body + excess_bytes)
2313
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2314
        self.assertEqual('aaaaa', decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2315
        self.assertEqual(excess_bytes, decoder.unused_data)
2316
        self.assertEqual(
2317
            1, decoder.next_read_size(),
2318
            "next_read_size hint should be 1 when finished_reading.")
2319
2320
    def test_multidigit_length(self):
2321
        """Lengths in the chunk prefixes can have multiple digits."""
2322
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2323
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2324
        length = 0x123
2325
        chunk_prefix = hex(length) + '\n'
2326
        chunk_bytes = 'z' * length
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2327
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2328
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
2329
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2330
        self.assertEqual(chunk_bytes, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2331
2332
    def test_byte_at_a_time(self):
2333
        """A complete body fed to the decoder one byte at a time should not
2334
        confuse the decoder.  That is, it should give the same result as if the
2335
        bytes had been received in one batch.
2336
2337
        This test is the same as test_one_chunk apart from the way accept_bytes
2338
        is called.
2339
        """
2340
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2341
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2342
        chunk_length = 'f\n'
2343
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2344
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2345
        for byte in (chunk_length + chunk_content + finish):
2346
            decoder.accept_bytes(byte)
2347
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2348
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2349
        self.assertEqual('', decoder.unused_data)
2350
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2351
    def test_read_pending_data_resets(self):
2352
        """read_pending_data does not return the same bytes twice."""
2353
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2354
        decoder.accept_bytes('chunked\n')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2355
        chunk_one = '3\naaa'
2356
        chunk_two = '3\nbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2357
        finish = 'END\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2358
        decoder.accept_bytes(chunk_one)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2359
        self.assertEqual('aaa', decoder.read_next_chunk())
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2360
        decoder.accept_bytes(chunk_two)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2361
        self.assertEqual('bbb', decoder.read_next_chunk())
2362
        self.assertEqual(None, decoder.read_next_chunk())
2363
2364
    def test_decode_error(self):
2365
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2366
        decoder.accept_bytes('chunked\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2367
        chunk_one = 'b\nfirst chunk'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2368
        error_signal = 'ERR\n'
2369
        error_chunks = '5\npart1' + '5\npart2'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2370
        finish = 'END\n'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2371
        decoder.accept_bytes(chunk_one + error_signal + error_chunks + finish)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2372
        self.assertTrue(decoder.finished_reading)
2373
        self.assertEqual('first chunk', decoder.read_next_chunk())
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2374
        expected_failure = _mod_request.FailedSmartServerResponse(
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2375
            ('part1', 'part2'))
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2376
        self.assertEqual(expected_failure, decoder.read_next_chunk())
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2377
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2378
    def test_bad_header(self):
2379
        """accept_bytes raises a SmartProtocolError if a chunked body does not
2380
        start with the right header.
2381
        """
2382
        decoder = protocol.ChunkedBodyDecoder()
2383
        self.assertRaises(
2384
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
2385
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2386
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2387
class TestSuccessfulSmartServerResponse(tests.TestCase):
2388
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2389
    def test_construct_no_body(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2390
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2391
        self.assertEqual(('foo', 'bar'), response.args)
2392
        self.assertEqual(None, response.body)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2393
2394
    def test_construct_with_body(self):
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2395
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'),
2396
                                                              'bytes')
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2397
        self.assertEqual(('foo', 'bar'), response.args)
2398
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
2399
        # repr(response) doesn't trigger exceptions.
2400
        repr(response)
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2401
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2402
    def test_construct_with_body_stream(self):
2403
        bytes_iterable = ['abc']
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2404
        response = _mod_request.SuccessfulSmartServerResponse(
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2405
            ('foo', 'bar'), body_stream=bytes_iterable)
2406
        self.assertEqual(('foo', 'bar'), response.args)
2407
        self.assertEqual(bytes_iterable, response.body_stream)
2408
2409
    def test_construct_rejects_body_and_body_stream(self):
2410
        """'body' and 'body_stream' are mutually exclusive."""
2411
        self.assertRaises(
2412
            errors.BzrError,
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2413
            _mod_request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2414
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2415
    def test_is_successful(self):
2416
        """is_successful should return True for SuccessfulSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2417
        response = _mod_request.SuccessfulSmartServerResponse(('error',))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2418
        self.assertEqual(True, response.is_successful())
2419
2420
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2421
class TestFailedSmartServerResponse(tests.TestCase):
2422
2423
    def test_construct(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2424
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2425
        self.assertEqual(('foo', 'bar'), response.args)
2426
        self.assertEqual(None, response.body)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2427
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2428
        self.assertEqual(('foo', 'bar'), response.args)
2429
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
2430
        # repr(response) doesn't trigger exceptions.
2431
        repr(response)
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2432
2433
    def test_is_successful(self):
2434
        """is_successful should return False for FailedSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2435
        response = _mod_request.FailedSmartServerResponse(('error',))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2436
        self.assertEqual(False, response.is_successful())
2437
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2438
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2439
class FakeHTTPMedium(object):
2440
    def __init__(self):
2441
        self.written_request = None
2442
        self._current_request = None
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
2443
    def send_http_smart_request(self, bytes):
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2444
        self.written_request = bytes
2445
        return None
2446
2447
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
2448
class HTTPTunnellingSmokeTest(tests.TestCase):
2449
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
2450
    def setUp(self):
2451
        super(HTTPTunnellingSmokeTest, self).setUp()
2452
        # We use the VFS layer as part of HTTP tunnelling tests.
2402.1.2 by Andrew Bennetts
Deal with review comments.
2453
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
2454
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2455
    def test_smart_http_medium_request_accept_bytes(self):
2456
        medium = FakeHTTPMedium()
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
2457
        request = SmartClientHTTPMediumRequest(medium)
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2458
        request.accept_bytes('abc')
2459
        request.accept_bytes('def')
2460
        self.assertEqual(None, medium.written_request)
2461
        request.finished_writing()
2462
        self.assertEqual('abcdef', medium.written_request)
2463
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
2464
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2465
class RemoteHTTPTransportTestCase(tests.TestCase):
2208.4.2 by Andrew Bennetts
Always POST to the same .bzr/smart URL for a given branch, even when accessing files in subdirectories.
2466
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
2467
    def test_remote_path_after_clone_child(self):
2208.4.2 by Andrew Bennetts
Always POST to the same .bzr/smart URL for a given branch, even when accessing files in subdirectories.
2468
        # If a user enters "bzr+http://host/foo", we want to sent all smart
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
2469
        # requests for child URLs of that to the original URL.  i.e., we want to
2470
        # POST to "bzr+http://host/foo/.bzr/smart" and never something like
2471
        # "bzr+http://host/foo/.bzr/branch/.bzr/smart".  So, a cloned
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2472
        # RemoteHTTPTransport remembers the initial URL, and adjusts the relpaths
2208.4.2 by Andrew Bennetts
Always POST to the same .bzr/smart URL for a given branch, even when accessing files in subdirectories.
2473
        # it sends in smart requests accordingly.
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2474
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/path')
2208.4.2 by Andrew Bennetts
Always POST to the same .bzr/smart URL for a given branch, even when accessing files in subdirectories.
2475
        new_transport = base_transport.clone('child_dir')
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
2476
        self.assertEqual(base_transport._http_transport,
2477
                         new_transport._http_transport)
2208.4.2 by Andrew Bennetts
Always POST to the same .bzr/smart URL for a given branch, even when accessing files in subdirectories.
2478
        self.assertEqual('child_dir/foo', new_transport._remote_path('foo'))
2479
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
2480
    def test_remote_path_unnormal_base(self):
2481
        # If the transport's base isn't normalised, the _remote_path should
2482
        # still be calculated correctly.
2483
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
2484
        self.assertEqual('c', base_transport._remote_path('c'))
2485
2486
    def test_clone_unnormal_base(self):
2487
        # If the transport's base isn't normalised, cloned transports should
2488
        # still work correctly.
2489
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
2490
        new_transport = base_transport.clone('c')
2491
        self.assertEqual('bzr+http://host/%7Ea/b/c/', new_transport.base)
2492
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2493
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
2494
# TODO: Client feature that does get_bundle and then installs that into a
2495
# branch; this can be used in place of the regular pull/fetch operation when
2496
# coming from a smart server.
2497
#
2498
# TODO: Eventually, want to do a 'branch' command by fetching the whole
2499
# history as one big bundle.  How?  
2500
#
2501
# The branch command does 'br_from.sprout', which tries to preserve the same
2502
# format.  We don't necessarily even want that.  
2503
#
2504
# It might be simpler to handle cmd_pull first, which does a simpler fetch()
2505
# operation from one branch into another.  It already has some code for
2506
# pulling from a bundle, which it does by trying to see if the destination is
2507
# a bundle file.  So it seems the logic for pull ought to be:
2508
# 
2509
#  - if it's a smart server, get a bundle from there and install that
2510
#  - if it's a bundle, install that
2511
#  - if it's a branch, pull from there
2512
#
2513
# Getting a bundle from a smart server is a bit different from reading a
2514
# bundle from a URL:
2515
#
2516
#  - we can reasonably remember the URL we last read from 
2517
#  - you can specify a revision number to pull, and we need to pass it across
2518
#    to the server as a limit on what will be requested
2519
#
2520
# TODO: Given a URL, determine whether it is a smart server or not (or perhaps
2521
# otherwise whether it's a bundle?)  Should this be a property or method of
2522
# the transport?  For the ssh protocol, we always know it's a smart server.
2523
# For http, we potentially need to probe.  But if we're explicitly given
2524
# bzr+http:// then we can skip that for now.