/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()
436
    
437
    def test_tcp_client_ignores_disconnect_when_not_connected(self):
438
        # 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.
439
        # 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.
440
        client_medium = medium.SmartTCPClientMedium(None, None)
441
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
442
443
    def test_tcp_client_raises_on_read_when_not_connected(self):
444
        # 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.
445
        # MediumNotConnected.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
446
        client_medium = medium.SmartTCPClientMedium(None, None)
447
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 0)
448
        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.
449
450
    def test_tcp_client_supports__flush(self):
451
        # invoking _flush on a TCPClientMedium should do something useful.
452
        # RBC 20060922 not sure how to test/tell in this case.
453
        sock, medium = self.make_loopsocket_and_medium()
454
        bytes = []
455
        t = self.receive_bytes_on_server(sock, bytes)
456
        # try with nothing buffered
457
        medium._flush()
458
        medium._accept_bytes('ab')
459
        # and with something sent.
460
        medium._flush()
461
        medium.disconnect()
462
        t.join()
463
        sock.close()
464
        self.assertEqual(['ab'], bytes)
465
        # now disconnect again : this should not do anything, if disconnection
466
        # really did disconnect.
467
        medium.disconnect()
468
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
469
    def test_tcp_client_host_unknown_connection_error(self):
470
        self.requireFeature(InvalidHostnameFeature)
471
        client_medium = medium.SmartTCPClientMedium(
472
            'non_existent.invalid', 4155)
473
        self.assertRaises(
474
            errors.ConnectionError, client_medium._ensure_connection)
475
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
476
477
class TestSmartClientStreamMediumRequest(tests.TestCase):
478
    """Tests the for SmartClientStreamMediumRequest.
479
    
480
    SmartClientStreamMediumRequest is a helper for the three stream based 
481
    mediums: TCP, SSH, SimplePipes, so we only test it once, and then test that
482
    those three mediums implement the interface it expects.
483
    """
484
485
    def test_accept_bytes_after_finished_writing_errors(self):
486
        # calling accept_bytes after calling finished_writing raises 
487
        # WritingCompleted to prevent bad assumptions on stream environments
488
        # breaking the needs of message-based environments.
489
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
490
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
491
        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.
492
        request.finished_writing()
493
        self.assertRaises(errors.WritingCompleted, request.accept_bytes, None)
494
495
    def test_accept_bytes(self):
496
        # accept bytes should invoke _accept_bytes on the stream medium.
497
        # we test this by using the SimplePipes medium - the most trivial one
498
        # and checking that the pipes get the data.
499
        input = StringIO()
500
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
501
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
502
        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.
503
        request.accept_bytes('123')
504
        request.finished_writing()
505
        request.finished_reading()
506
        self.assertEqual('', input.getvalue())
507
        self.assertEqual('123', output.getvalue())
508
509
    def test_construct_sets_stream_request(self):
510
        # constructing a SmartClientStreamMediumRequest on a StreamMedium sets
511
        # the current request to the new SmartClientStreamMediumRequest
512
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
513
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
514
        request = medium.SmartClientStreamMediumRequest(client_medium)
515
        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.
516
517
    def test_construct_while_another_request_active_throws(self):
518
        # constructing a SmartClientStreamMediumRequest on a StreamMedium with
519
        # a non-None _current_request raises TooManyConcurrentRequests.
520
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
521
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
522
        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.
523
        self.assertRaises(errors.TooManyConcurrentRequests,
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
524
            medium.SmartClientStreamMediumRequest, client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
525
526
    def test_finished_read_clears_current_request(self):
527
        # calling finished_reading clears the current request from the requests
528
        # medium
529
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
530
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
531
        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.
532
        request.finished_writing()
533
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
534
        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.
535
536
    def test_finished_read_before_finished_write_errors(self):
537
        # calling finished_reading before calling finished_writing triggers a
538
        # WritingNotComplete error.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
539
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
540
        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.
541
        self.assertRaises(errors.WritingNotComplete, request.finished_reading)
542
        
543
    def test_read_bytes(self):
544
        # read bytes should invoke _read_bytes on the stream medium.
545
        # we test this by using the SimplePipes medium - the most trivial one
546
        # and checking that the data is supplied. Its possible that a 
547
        # faulty implementation could poke at the pipe variables them selves,
548
        # but we trust that this will be caught as it will break the integration
549
        # smoke tests.
550
        input = StringIO('321')
551
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
552
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
553
        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.
554
        request.finished_writing()
555
        self.assertEqual('321', request.read_bytes(3))
556
        request.finished_reading()
557
        self.assertEqual('', input.read())
558
        self.assertEqual('', output.getvalue())
559
560
    def test_read_bytes_before_finished_write_errors(self):
561
        # calling read_bytes before calling finished_writing triggers a
562
        # WritingNotComplete error because the Smart protocol is designed to be
563
        # compatible with strict message based protocols like HTTP where the
564
        # request cannot be submitted until the writing has completed.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
565
        client_medium = medium.SmartSimplePipesClientMedium(None, None)
566
        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.
567
        self.assertRaises(errors.WritingNotComplete, request.read_bytes, None)
568
569
    def test_read_bytes_after_finished_reading_errors(self):
570
        # calling read_bytes after calling finished_reading raises 
571
        # ReadingCompleted to prevent bad assumptions on stream environments
572
        # breaking the needs of message-based environments.
573
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
574
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
575
        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.
576
        request.finished_writing()
577
        request.finished_reading()
578
        self.assertRaises(errors.ReadingCompleted, request.read_bytes, None)
579
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
580
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
581
class RemoteTransportTests(TestCaseWithSmartMedium):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
582
583
    def test_plausible_url(self):
584
        self.assert_(self.get_url().startswith('bzr://'))
585
586
    def test_probe_transport(self):
587
        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)
588
        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
589
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
590
    def test_get_medium_from_transport(self):
591
        """Remote transport has a medium always, which it can return."""
592
        t = self.get_transport()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
593
        client_medium = t.get_smart_medium()
594
        self.assertIsInstance(client_medium, medium.SmartClientMedium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
595
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
596
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
597
class ErrorRaisingProtocol(object):
598
599
    def __init__(self, exception):
600
        self.exception = exception
601
602
    def next_read_size(self):
603
        raise self.exception
604
605
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
606
class SampleRequest(object):
607
    
608
    def __init__(self, expected_bytes):
609
        self.accepted_bytes = ''
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
610
        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.
611
        self.expected_bytes = expected_bytes
612
        self.excess_buffer = ''
613
614
    def accept_bytes(self, bytes):
615
        self.accepted_bytes += bytes
616
        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.
617
            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.
618
            self.excess_buffer = self.accepted_bytes[len(self.expected_bytes):]
619
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
620
    def next_read_size(self):
621
        if self._finished_reading:
622
            return 0
623
        else:
624
            return 1
625
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
626
627
class TestSmartServerStreamMedium(tests.TestCase):
628
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)
629
    def setUp(self):
630
        super(TestSmartServerStreamMedium, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
631
        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)
632
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
633
    def portable_socket_pair(self):
634
        """Return a pair of TCP sockets connected to each other.
635
        
636
        Unlike socket.socketpair, this should work on Windows.
637
        """
638
        listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
639
        listen_sock.bind(('127.0.0.1', 0))
640
        listen_sock.listen(1)
641
        client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
642
        client_sock.connect(listen_sock.getsockname())
643
        server_sock, addr = listen_sock.accept()
644
        listen_sock.close()
645
        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
646
    
647
    def test_smart_query_version(self):
648
        """Feed a canned query version to a server"""
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
649
        # 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
650
        to_server = StringIO('hello\n')
651
        from_server = StringIO()
2018.2.27 by Andrew Bennetts
Merge from bzr.dev
652
        transport = local.LocalTransport(urlutils.local_path_to_url('/'))
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
653
        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.
654
            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
655
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
656
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
657
        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.
658
        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
659
                         from_server.getvalue())
660
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
661
    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
662
        transport = memory.MemoryTransport('memory:///')
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
663
        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
664
        to_server = StringIO('get\001./testfile\n')
665
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
666
        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.
667
            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
668
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
669
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
670
        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
671
        self.assertEqual('ok\n'
672
                         '17\n'
673
                         'contents\nof\nfile\n'
674
                         'done\n',
675
                         from_server.getvalue())
676
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
677
    def test_response_to_canned_get_of_utf8(self):
678
        # wire-to-wire, using the whole stack, with a UTF-8 filename.
679
        transport = memory.MemoryTransport('memory:///')
680
        utf8_filename = u'testfile\N{INTERROBANG}'.encode('utf-8')
681
        transport.put_bytes(utf8_filename, 'contents\nof\nfile\n')
682
        to_server = StringIO('get\001' + utf8_filename + '\n')
683
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
684
        server = medium.SmartServerPipeStreamMedium(
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
685
            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
686
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
687
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
688
        server._serve_one_request(smart_protocol)
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
689
        self.assertEqual('ok\n'
690
                         '17\n'
691
                         'contents\nof\nfile\n'
692
                         'done\n',
693
                         from_server.getvalue())
694
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
695
    def test_pipe_like_stream_with_bulk_data(self):
696
        sample_request_bytes = 'command\n9\nbulk datadone\n'
697
        to_server = StringIO(sample_request_bytes)
698
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
699
        server = medium.SmartServerPipeStreamMedium(
700
            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.
701
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
702
        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.
703
        self.assertEqual('', from_server.getvalue())
704
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
705
        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.
706
707
    def test_socket_stream_with_bulk_data(self):
708
        sample_request_bytes = 'command\n9\nbulk datadone\n'
709
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
710
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
711
            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.
712
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
713
        client_sock.sendall(sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
714
        server._serve_one_request(sample_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
715
        server_sock.close()
716
        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.
717
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
718
        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.
719
720
    def test_pipe_like_stream_shutdown_detection(self):
721
        to_server = StringIO('')
722
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
723
        server = medium.SmartServerPipeStreamMedium(to_server, from_server, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
724
        server._serve_one_request(SampleRequest('x'))
725
        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.
726
        
727
    def test_socket_stream_shutdown_detection(self):
728
        server_sock, client_sock = self.portable_socket_pair()
729
        client_sock.close()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
730
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
731
            server_sock, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
732
        server._serve_one_request(SampleRequest('x'))
733
        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.
734
        
735
    def test_pipe_like_stream_with_two_requests(self):
736
        # If two requests are read in one go, then two calls to
737
        # _serve_one_request should still process both of them as if they had
738
        # been received seperately.
739
        sample_request_bytes = 'command\n'
740
        to_server = StringIO(sample_request_bytes * 2)
741
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
742
        server = medium.SmartServerPipeStreamMedium(
743
            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.
744
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
745
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
746
        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.
747
        self.assertEqual('', from_server.getvalue())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
748
        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.
749
        # Make a new protocol, call _serve_one_request with it to collect the
750
        # second request.
751
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
752
        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.
753
        self.assertEqual('', from_server.getvalue())
754
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
755
        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.
756
        
757
    def test_socket_stream_with_two_requests(self):
758
        # If two requests are read in one go, then two calls to
759
        # _serve_one_request should still process both of them as if they had
760
        # been received seperately.
761
        sample_request_bytes = 'command\n'
762
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
763
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
764
            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.
765
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
766
        # Put two whole requests on the wire.
767
        client_sock.sendall(sample_request_bytes * 2)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
768
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
769
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
770
        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.
771
        # Make a new protocol, call _serve_one_request with it to collect the
772
        # second request.
773
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
774
        stream_still_open = server._serve_one_request(second_protocol)
775
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
776
        self.assertFalse(server.finished)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
777
        server_sock.close()
778
        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.
779
780
    def test_pipe_like_stream_error_handling(self):
781
        # Use plain python StringIO so we can monkey-patch the close method to
782
        # not discard the contents.
783
        from StringIO import StringIO
784
        to_server = StringIO('')
785
        from_server = StringIO()
786
        self.closed = False
787
        def close():
788
            self.closed = True
789
        from_server.close = close
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
790
        server = medium.SmartServerPipeStreamMedium(
791
            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.
792
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
793
        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.
794
        self.assertEqual('', from_server.getvalue())
795
        self.assertTrue(self.closed)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
796
        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.
797
        
798
    def test_socket_stream_error_handling(self):
799
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
800
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
801
            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.
802
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
803
        server._serve_one_request(fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
804
        # recv should not block, because the other end of the socket has been
805
        # closed.
806
        self.assertEqual('', client_sock.recv(1))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
807
        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.
808
        
809
    def test_pipe_like_stream_keyboard_interrupt_handling(self):
810
        to_server = StringIO('')
811
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
812
        server = medium.SmartServerPipeStreamMedium(
813
            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.
814
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
815
        self.assertRaises(
816
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
817
        self.assertEqual('', from_server.getvalue())
818
819
    def test_socket_stream_keyboard_interrupt_handling(self):
820
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
821
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
822
            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.
823
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
824
        self.assertRaises(
825
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
826
        server_sock.close()
827
        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.
828
829
    def build_protocol_pipe_like(self, bytes):
830
        to_server = StringIO(bytes)
831
        from_server = StringIO()
832
        server = medium.SmartServerPipeStreamMedium(
833
            to_server, from_server, None)
834
        return server._build_protocol()
835
836
    def build_protocol_socket(self, bytes):
837
        server_sock, client_sock = self.portable_socket_pair()
838
        server = medium.SmartServerSocketStreamMedium(
839
            server_sock, None)
840
        client_sock.sendall(bytes)
841
        client_sock.close()
842
        return server._build_protocol()
843
844
    def assertProtocolOne(self, server_protocol):
845
        # Use assertIs because assertIsInstance will wrongly pass
846
        # SmartServerRequestProtocolTwo (because it subclasses
847
        # SmartServerRequestProtocolOne).
848
        self.assertIs(
849
            type(server_protocol), protocol.SmartServerRequestProtocolOne)
850
851
    def assertProtocolTwo(self, server_protocol):
852
        self.assertIsInstance(
853
            server_protocol, protocol.SmartServerRequestProtocolTwo)
854
855
    def test_pipe_like_build_protocol_empty_bytes(self):
856
        # Any empty request (i.e. no bytes) is detected as protocol version one.
857
        server_protocol = self.build_protocol_pipe_like('')
858
        self.assertProtocolOne(server_protocol)
859
        
860
    def test_socket_like_build_protocol_empty_bytes(self):
861
        # Any empty request (i.e. no bytes) is detected as protocol version one.
862
        server_protocol = self.build_protocol_socket('')
863
        self.assertProtocolOne(server_protocol)
864
865
    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.
866
        # A request that doesn't start with "bzr request 2\n" is version one.
867
        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.
868
        self.assertProtocolOne(server_protocol)
869
870
    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.
871
        # A request that doesn't start with "bzr request 2\n" is version one.
872
        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.
873
        self.assertProtocolOne(server_protocol)
874
875
    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.
876
        # A request that starts with "bzr request 2\n" is version two.
877
        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.
878
        self.assertProtocolTwo(server_protocol)
879
880
    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.
881
        # A request that starts with "bzr request 2\n" is version two.
882
        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.
883
        self.assertProtocolTwo(server_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
884
        
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
885
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
886
class TestSmartTCPServer(tests.TestCase):
887
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
888
    def test_get_error_unexpected(self):
889
        """Error reported by server with no specific representation"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
890
        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
891
        class FlakyTransport(object):
2376.3.3 by Robert Collins
Fix all smart_transport tests.
892
            base = 'a_url'
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
893
            def external_url(self):
894
                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.
895
            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
896
                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.
897
        smart_server = server.SmartTCPServer(backing_transport=FlakyTransport())
898
        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
899
        try:
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
900
            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
901
            try:
902
                transport.get('something')
903
            except errors.TransportError, e:
904
                self.assertContainsRe(str(e), 'some random exception')
905
            else:
906
                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.
907
            transport.disconnect()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
908
        finally:
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
909
            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
910
911
912
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
913
    """Tests for connection/end to end behaviour using the TCP server.
914
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
915
    All of these tests are run with a server running on another thread serving
916
    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`.
917
918
    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
919
    """
920
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
921
    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`.
922
        """Setup the server.
923
924
        :param readonly: Create a readonly server.
925
        """
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
926
        if not backing_transport:
927
            self.backing_transport = memory.MemoryTransport()
928
        else:
929
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
930
        if readonly:
931
            self.real_backing_transport = self.backing_transport
932
            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.
933
        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
934
        self.server.start_background_thread()
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
935
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
936
        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
937
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
938
    def tearDownServer(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
939
        if getattr(self, 'transport', None):
940
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
941
            del self.transport
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
942
        if getattr(self, 'server', None):
943
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
944
            del self.server
945
946
947
class TestServerSocketUsage(SmartTCPTests):
948
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.
949
    def test_server_setup_teardown(self):
950
        """It should be safe to teardown the server with no requests."""
951
        self.setUpServer()
952
        server = self.server
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
953
        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.
954
        self.tearDownServer()
955
        self.assertRaises(errors.ConnectionError, transport.has, '.')
956
957
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
958
        """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
959
        self.setUpServer()
2370.4.2 by Robert Collins
Review feedback.
960
        server = self.server
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
961
        self.transport.has('.')
962
        self.tearDownServer()
963
        # if the listening socket has closed, we should get a BADFD error
964
        # when connecting, rather than a hang.
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
965
        transport = remote.RemoteTCPTransport(server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
966
        self.assertRaises(errors.ConnectionError, transport.has, '.')
967
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
968
969
class WritableEndToEndTests(SmartTCPTests):
970
    """Client to server tests that require a writable transport."""
971
972
    def setUp(self):
973
        super(WritableEndToEndTests, self).setUp()
974
        self.setUpServer()
975
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
976
    def test_start_tcp_server(self):
977
        url = self.server.get_url()
978
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
979
980
    def test_smart_transport_has(self):
981
        """Checking for file existence over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
982
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
983
        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
984
        self.assertTrue(self.transport.has("foo"))
985
        self.assertFalse(self.transport.has("non-foo"))
986
987
    def test_smart_transport_get(self):
988
        """Read back a file over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
989
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
990
        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
991
        fp = self.transport.get("foo")
992
        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`.
993
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
994
    def test_get_error_enoent(self):
995
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
996
        # The path in a raised NoSuchFile exception should be the precise path
997
        # asked for by the client. This gives meaningful and unsurprising errors
998
        # for users.
2402.1.2 by Andrew Bennetts
Deal with review comments.
999
        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
1000
        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.
1001
            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
1002
        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.
1003
            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
1004
        else:
1005
            self.fail("get did not raise expected error")
1006
1007
    def test_simple_clone_conn(self):
1008
        """Test that cloning reuses the same connection."""
1009
        # we create a real connection not a loopback one, but it will use the
1010
        # 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__.
1011
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1012
        self.assertIs(self.transport.get_smart_medium(),
1013
                      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
1014
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)
1015
    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
1016
        self.assertEquals('/foo/bar',
1017
                          self.transport._remote_path('foo/bar'))
1018
1019
    def test_clone_changes_base(self):
1020
        """Cloning transport produces one with a new base location"""
1021
        conn2 = self.transport.clone('subdir')
1022
        self.assertEquals(self.transport.base + 'subdir/',
1023
                          conn2.base)
1024
1025
    def test_open_dir(self):
1026
        """Test changing directory"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1027
        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
1028
        transport = self.transport
1029
        self.backing_transport.mkdir('toffee')
1030
        self.backing_transport.mkdir('toffee/apple')
1031
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1032
        toffee_trans = transport.clone('toffee')
1033
        # Check that each transport has only the contents of its directory
1034
        # directly visible. If state was being held in the wrong object, it's
1035
        # conceivable that cloning a transport would alter the state of the
1036
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1037
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1038
        self.assertFalse(toffee_trans.has('toffee'))
1039
        self.assertFalse(transport.has('apple'))
1040
        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
1041
1042
    def test_open_bzrdir(self):
1043
        """Open an existing bzrdir over smart transport"""
1044
        transport = self.transport
1045
        t = self.backing_transport
1046
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
1047
        result_dir = bzrdir.BzrDir.open_containing_from_transport(transport)
1048
1049
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1050
class ReadOnlyEndToEndTests(SmartTCPTests):
1051
    """Tests from the client to the server using a readonly backing transport."""
1052
1053
    def test_mkdir_error_readonly(self):
1054
        """TransportNotPossible should be preserved from the backing transport."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1055
        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`.
1056
        self.setUpServer(readonly=True)
1057
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1058
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1059
1060
1061
class TestServerHooks(SmartTCPTests):
1062
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1063
    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
1064
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1065
        self.hook_calls.append((backing_urls, public_url))
1066
1067
    def test_server_started_hook_memory(self):
1068
        """The server_started hook fires when the server is started."""
1069
        self.hook_calls = []
1070
        server.SmartTCPServer.hooks.install_hook('server_started',
1071
            self.capture_server_call)
1072
        self.setUpServer()
1073
        # at this point, the server will be starting a thread up.
1074
        # there is no indicator at the moment, so bodge it by doing a request.
1075
        self.transport.has('.')
1076
        # The default test server uses MemoryTransport and that has no external
1077
        # url:
1078
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1079
            self.hook_calls)
1080
1081
    def test_server_started_hook_file(self):
1082
        """The server_started hook fires when the server is started."""
1083
        self.hook_calls = []
1084
        server.SmartTCPServer.hooks.install_hook('server_started',
1085
            self.capture_server_call)
1086
        self.setUpServer(backing_transport=get_transport("."))
1087
        # at this point, the server will be starting a thread up.
1088
        # there is no indicator at the moment, so bodge it by doing a request.
1089
        self.transport.has('.')
1090
        # The default test server uses MemoryTransport and that has no external
1091
        # url:
1092
        self.assertEqual([([
1093
            self.backing_transport.base, self.backing_transport.external_url()],
1094
             self.transport.base)],
1095
            self.hook_calls)
1096
1097
    def test_server_stopped_hook_simple_memory(self):
1098
        """The server_stopped hook fires when the server is stopped."""
1099
        self.hook_calls = []
1100
        server.SmartTCPServer.hooks.install_hook('server_stopped',
1101
            self.capture_server_call)
1102
        self.setUpServer()
1103
        result = [([self.backing_transport.base], self.transport.base)]
1104
        # check the stopping message isn't emitted up front.
1105
        self.assertEqual([], self.hook_calls)
1106
        # nor after a single message
1107
        self.transport.has('.')
1108
        self.assertEqual([], self.hook_calls)
1109
        # clean up the server
1110
        self.tearDownServer()
1111
        # now it should have fired.
1112
        self.assertEqual(result, self.hook_calls)
1113
1114
    def test_server_stopped_hook_simple_file(self):
1115
        """The server_stopped hook fires when the server is stopped."""
1116
        self.hook_calls = []
1117
        server.SmartTCPServer.hooks.install_hook('server_stopped',
1118
            self.capture_server_call)
1119
        self.setUpServer(backing_transport=get_transport("."))
1120
        result = [(
1121
            [self.backing_transport.base, self.backing_transport.external_url()]
1122
            , 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.
1123
        # check the stopping message isn't emitted up front.
1124
        self.assertEqual([], self.hook_calls)
1125
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1126
        self.transport.has('.')
1127
        self.assertEqual([], self.hook_calls)
1128
        # clean up the server
1129
        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.
1130
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1131
        self.assertEqual(result, self.hook_calls)
1132
1133
# TODO: test that when the server suffers an exception that it calls the
1134
# server-stopped hook.
1135
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1136
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1137
class SmartServerCommandTests(tests.TestCaseWithTransport):
1138
    """Tests that call directly into the command objects, bypassing the network
1139
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1140
1141
    Note: these tests are rudimentary versions of the command object tests in
1142
    test_remote.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1143
    """
1144
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1145
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1146
        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)
1147
        response = cmd.execute()
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1148
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1149
        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
1150
        
1151
    def test_get_bundle(self):
1152
        from bzrlib.bundle import serializer
1153
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1154
        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
1155
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1156
        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
1157
        
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1158
        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)
1159
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1160
        bundle = serializer.read_bundle(StringIO(response.body))
1161
        self.assertEqual((), response.args)
1162
1163
1164
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1165
    """Test that call directly into the handler logic, bypassing the network."""
1166
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)
1167
    def setUp(self):
1168
        super(SmartServerRequestHandlerTests, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
1169
        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)
1170
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1171
    def build_handler(self, transport):
1172
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1173
        return _mod_request.SmartServerRequestHandler(
1174
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1175
1176
    def test_construct_request_handler(self):
1177
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1178
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1179
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1180
        self.assertFalse(handler.finished_reading)
1181
1182
    def test_hello(self):
1183
        handler = self.build_handler(None)
1184
        handler.dispatch_command('hello', ())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1185
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1186
        self.assertEqual(None, handler.response.body)
1187
        
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)
1188
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1189
        # VFS handler classes will raise an error from "execute" if
1190
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1191
        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)
1192
        # set environment variable after construction to make sure it's
1193
        # examined.
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1194
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1195
        # 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)
1196
        # afterwards.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1197
        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)
1198
        self.assertRaises(errors.DisabledMethod, handler.execute)
1199
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1200
    def test_readonly_exception_becomes_transport_not_possible(self):
1201
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1202
        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`.
1203
        # send a mkdir for foo, with no explicit mode - should fail.
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1204
        handler.dispatch_command('mkdir', ('foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1205
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1206
        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`.
1207
        # XXX: TODO: test that other TransportNotPossible errors are
1208
        # presented as TransportNotPossible - not possible to do that
1209
        # until I figure out how to trigger that relatively cleanly via
1210
        # the api. RBC 20060918
1211
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1212
    def test_hello_has_finished_body_on_dispatch(self):
1213
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1214
        handler = self.build_handler(None)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1215
        handler.dispatch_command('hello', ())
1216
        self.assertTrue(handler.finished_reading)
1217
        self.assertNotEqual(None, handler.response)
1218
1219
    def test_put_bytes_non_atomic(self):
1220
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1221
        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
1222
        handler.dispatch_command('put_non_atomic', ('a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1223
        self.assertFalse(handler.finished_reading)
1224
        handler.accept_body('1234')
1225
        self.assertFalse(handler.finished_reading)
1226
        handler.accept_body('5678')
1227
        handler.end_of_body()
1228
        self.assertTrue(handler.finished_reading)
1229
        self.assertEqual(('ok', ), handler.response.args)
1230
        self.assertEqual(None, handler.response.body)
1231
        
1232
    def test_readv_accept_body(self):
1233
        """'readv' should set finished_reading after reading offsets."""
1234
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1235
        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
1236
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1237
        self.assertFalse(handler.finished_reading)
1238
        handler.accept_body('2,')
1239
        self.assertFalse(handler.finished_reading)
1240
        handler.accept_body('3')
1241
        handler.end_of_body()
1242
        self.assertTrue(handler.finished_reading)
1243
        self.assertEqual(('readv', ), handler.response.args)
1244
        # co - nte - nt of a-file is the file contents we are extracting from.
1245
        self.assertEqual('nte', handler.response.body)
1246
1247
    def test_readv_short_read_response_contents(self):
1248
        """'readv' when a short read occurs sets the response appropriately."""
1249
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1250
        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
1251
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1252
        # read beyond the end of the file.
1253
        handler.accept_body('100,1')
1254
        handler.end_of_body()
1255
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1256
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1257
            handler.response.args)
1258
        self.assertEqual(None, handler.response.body)
1259
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.
1260
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)
1261
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.
1262
1263
    def test_registration(self):
1264
        t = get_transport('bzr+ssh://example.com/path')
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1265
        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.
1266
        self.assertEqual('example.com', t._host)
1267
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1268
    def test_bzr_https(self):
1269
        # https://bugs.launchpad.net/bzr/+bug/128456
1270
        t = get_transport('bzr+https://example.com/path')
1271
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1272
        self.assertStartsWith(
1273
            t._http_transport.base,
1274
            'https://')
1275
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.
1276
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)
1277
class TestRemoteTransport(tests.TestCase):
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1278
        
1279
    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)
1280
        # 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.
1281
        input = StringIO("ok\n3\nbardone\n")
1282
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1283
        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)
1284
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1285
            'bzr://localhost/', medium=client_medium)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1286
1287
        # 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.
1288
        # method is called.  No data should have been sent, or read.
1289
        self.assertEqual(0, input.tell())
1290
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1291
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1292
        # Now call a method that should result in a single request : as the
1293
        # transport makes its own protocol instances, we check on the wire.
1294
        # XXX: TODO: give the transport a protocol factory, which can make
1295
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1296
        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.
1297
        # only the needed data should have been sent/received.
1298
        self.assertEqual(13, input.tell())
1299
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1300
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1301
    def test__translate_error_readonly(self):
1302
        """Sending a ReadOnlyError to _translate_error raises TransportNotPossible."""
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1303
        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)
1304
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1305
            'bzr://localhost/', medium=client_medium)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1306
        self.assertRaises(errors.TransportNotPossible,
1307
            transport._translate_error, ("ReadOnlyError", ))
1308
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1309
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1310
class InstrumentedServerProtocol(medium.SmartServerStreamMedium):
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.
1311
    """A smart server which is backed by memory and saves its write requests."""
1312
1313
    def __init__(self, write_output_list):
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1314
        medium.SmartServerStreamMedium.__init__(self, memory.MemoryTransport())
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.
1315
        self._write_output_list = write_output_list
1316
1317
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1318
class TestSmartProtocol(tests.TestCase):
1319
    """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.
1320
1321
    Each test case gets a smart_server and smart_client created during setUp().
1322
1323
    It is planned that the client can be called with self.call_client() giving
1324
    it an expected server response, which will be fed into it when it tries to
1325
    read. Likewise, self.call_server will call a servers method with a canned
1326
    serialised client request. Output done by the client or server for these
1327
    calls will be captured to self.to_server and self.to_client. Each element
1328
    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.
1329
1330
    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.
1331
    """
1332
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1333
    client_protocol_class = None
1334
    server_protocol_class = None
1335
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.
1336
    def setUp(self):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1337
        super(TestSmartProtocol, self).setUp()
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.
1338
        # XXX: self.server_to_client doesn't seem to be used.  If so,
1339
        # InstrumentedServerProtocol is redundant too.
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1340
        self.server_to_client = []
1341
        self.to_server = StringIO()
1342
        self.to_client = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1343
        self.client_medium = medium.SmartSimplePipesClientMedium(self.to_client,
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1344
            self.to_server)
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1345
        self.client_protocol = self.client_protocol_class(self.client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1346
        self.smart_server = InstrumentedServerProtocol(self.server_to_client)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1347
        self.smart_server_request = _mod_request.SmartServerRequestHandler(
1348
            None, _mod_request.request_handlers, root_client_path='/')
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.
1349
1350
    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.
1351
        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.
1352
        """Check that smart (de)serialises offsets as expected.
1353
        
1354
        We check both serialisation and deserialisation at the same time
1355
        to ensure that the round tripping cannot skew: both directions should
1356
        be as expected.
1357
        
1358
        :param expected_offsets: a readv offset list.
1359
        :param expected_seralised: an expected serial form of the offsets.
1360
        """
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.
1361
        # XXX: '_deserialise_offsets' should be a method of the
1362
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1363
        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.
1364
        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.
1365
        self.assertEqual(expected_offsets, offsets)
1366
        serialised = client._serialise_offsets(offsets)
1367
        self.assertEqual(expected_serialised, serialised)
1368
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1369
    def build_protocol_waiting_for_body(self):
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1370
        out_stream = StringIO()
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1371
        smart_protocol = self.server_protocol_class(None, out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1372
        smart_protocol.has_dispatched = True
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1373
        smart_protocol.request = self.smart_server_request
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1374
        class FakeCommand(object):
1375
            def do_body(cmd, body_bytes):
1376
                self.end_received = True
1377
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1378
                return _mod_request.SuccessfulSmartServerResponse(('ok', ))
2018.5.12 by Andrew Bennetts
Rename SmartServerRequestHandler's command attribute to _command; it's private.
1379
        smart_protocol.request._command = FakeCommand()
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1380
        # Call accept_bytes to make sure that internal state like _body_decoder
1381
        # is initialised.  This test should probably be given a clearer
1382
        # interface to work with that will not cause this inconsistency.
1383
        #   -- 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
1384
        smart_protocol.accept_bytes('')
1385
        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.
1386
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1387
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
1388
            input_tuples):
1389
        """Assert that each input_tuple serialises as expected_bytes, and the
1390
        bytes deserialise as expected_tuple.
1391
        """
1392
        # check the encoding of the server for all input_tuples matches
1393
        # expected bytes
1394
        for input_tuple in input_tuples:
1395
            server_output = StringIO()
1396
            server_protocol = self.server_protocol_class(
1397
                None, server_output.write)
2432.4.4 by Robert Collins
Merge hpss-protocol2.
1398
            server_protocol._send_response(
1399
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1400
            self.assertEqual(expected_bytes, server_output.getvalue())
1401
        # check the decoding of the client smart_protocol from expected_bytes:
1402
        input = StringIO(expected_bytes)
1403
        output = StringIO()
1404
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1405
        request = client_medium.get_request()
1406
        smart_protocol = self.client_protocol_class(request)
1407
        smart_protocol.call('foo')
1408
        self.assertEqual(expected_tuple, smart_protocol.read_response_tuple())
1409
1410
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.
1411
class CommonSmartProtocolTestMixin(object):
1412
1413
    def test_errors_are_logged(self):
1414
        """If an error occurs during testing, it is logged to the test log."""
1415
        out_stream = StringIO()
1416
        smart_protocol = self.server_protocol_class(None, out_stream.write)
1417
        # This triggers a "bad request" error.
1418
        smart_protocol.accept_bytes('abc\n')
1419
        test_log = self._get_log(keep_log_file=True)
1420
        self.assertContainsRe(test_log, 'Traceback')
1421
        self.assertContainsRe(test_log, 'SmartProtocolError')
1422
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1423
    def test_connection_closed_reporting(self):
1424
        input = StringIO()
1425
        output = StringIO()
1426
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1427
        request = client_medium.get_request()
1428
        smart_protocol = self.client_protocol_class(request)
1429
        smart_protocol.call('hello')
1430
        ex = self.assertRaises(errors.ConnectionReset, 
1431
            smart_protocol.read_response_tuple)
1432
        self.assertEqual("Connection closed: "
1433
            "please check connectivity and permissions "
1434
            "(and try -Dhpss if further diagnosis is required)", str(ex))
1435
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.
1436
1437
class TestSmartProtocolOne(TestSmartProtocol, CommonSmartProtocolTestMixin):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1438
    """Tests for the smart protocol version one."""
1439
1440
    client_protocol_class = protocol.SmartClientRequestProtocolOne
1441
    server_protocol_class = protocol.SmartServerRequestProtocolOne
1442
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1443
    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
1444
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
1445
        self.assertEqual('', smart_protocol.excess_buffer)
1446
        self.assertEqual('', smart_protocol.in_buffer)
1447
        self.assertFalse(smart_protocol.has_dispatched)
1448
        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.
1449
1450
    def test_construct_version_one_client_protocol(self):
1451
        # we can construct a client protocol from a client medium request
1452
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1453
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
1454
        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
1455
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1456
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.
1457
    def test_server_offset_serialisation(self):
1458
        """The Smart protocol serialises offsets as a comma and \n string.
1459
1460
        We check a number of boundary cases are as expected: empty, one offset,
1461
        one with the order of reads not increasing (an out of order read), and
1462
        one that should coalesce.
1463
        """
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.
1464
        self.assertOffsetSerialisation([], '', self.client_protocol)
1465
        self.assertOffsetSerialisation([(1,2)], '1,2', self.client_protocol)
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.
1466
        self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
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.
1467
            self.client_protocol)
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.
1468
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
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.
1469
            '1,2\n3,4\n100,200', self.client_protocol)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1470
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1471
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1472
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1473
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1474
            None, out_stream.write)
1475
        smart_protocol.accept_bytes('abc')
1476
        self.assertEqual('abc', smart_protocol.in_buffer)
1477
        smart_protocol.accept_bytes('\n')
1478
        self.assertEqual(
1479
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
1480
            out_stream.getvalue())
1481
        self.assertTrue(smart_protocol.has_dispatched)
1482
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
1483
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1484
    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.
1485
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1486
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1487
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1488
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1489
        protocol.accept_bytes('defgd')
1490
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1491
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1492
        self.assertTrue(self.end_received)
1493
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1494
    def test_accept_request_and_body_all_at_once(self):
2402.1.2 by Andrew Bennetts
Deal with review comments.
1495
        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.
1496
        mem_transport = memory.MemoryTransport()
1497
        mem_transport.put_bytes('foo', 'abcdefghij')
1498
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1499
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
1500
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1501
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1502
        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.
1503
        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
1504
        self.assertEqual('', smart_protocol.excess_buffer)
1505
        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.
1506
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1507
    def test_accept_excess_bytes_are_preserved(self):
1508
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1509
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1510
            None, out_stream.write)
1511
        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.
1512
        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
1513
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1514
        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.
1515
1516
    def test_accept_excess_bytes_after_body(self):
1517
        protocol = self.build_protocol_waiting_for_body()
1518
        protocol.accept_bytes('7\nabcdefgdone\nX')
1519
        self.assertTrue(self.end_received)
1520
        self.assertEqual("X", protocol.excess_buffer)
1521
        self.assertEqual("", protocol.in_buffer)
1522
        protocol.accept_bytes('Y')
1523
        self.assertEqual("XY", protocol.excess_buffer)
1524
        self.assertEqual("", protocol.in_buffer)
1525
1526
    def test_accept_excess_bytes_after_dispatch(self):
1527
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1528
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1529
            None, out_stream.write)
1530
        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.
1531
        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
1532
        smart_protocol.accept_bytes('hel')
1533
        self.assertEqual("hel", smart_protocol.excess_buffer)
1534
        smart_protocol.accept_bytes('lo\n')
1535
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1536
        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.
1537
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1538
    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
1539
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1540
            None, lambda x: None)
1541
        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.
1542
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1543
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1544
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1545
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1546
    def test__send_response_errors_with_base_response(self):
1547
        """Ensure that only the Successful/Failed subclasses are used."""
1548
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1549
            None, lambda x: None)
1550
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1551
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1552
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1553
    def test_query_version(self):
1554
        """query_version on a SmartClientProtocolOne should return a number.
1555
        
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1556
        The protocol provides the query_version because the domain level clients
1557
        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.
1558
        """
1559
        # What we really want to test here is that SmartClientProtocolOne calls
1560
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1561
        # 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.
1562
        # 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.
1563
        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.
1564
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1565
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1566
        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
1567
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1568
        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.
1569
1570
    def test_client_call_empty_response(self):
1571
        # protocol.call() can get back an empty tuple as a response. This occurs
1572
        # when the parsed line is an empty line, and results in a tuple with
1573
        # one element - an empty string.
1574
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
1575
1576
    def test_client_call_three_element_response(self):
1577
        # protocol.call() can get back tuples of other lengths. A three element
1578
        # tuple should be unpacked as three strings.
1579
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
1580
            [('a', 'b', '34')])
1581
1582
    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.
1583
        # 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.
1584
        # wire.
1585
        expected_bytes = "foo\n7\nabcdefgdone\n"
1586
        input = StringIO("\n")
1587
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1588
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1589
        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
1590
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1591
        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.
1592
        self.assertEqual(expected_bytes, output.getvalue())
1593
1594
    def test_client_call_with_body_readv_array(self):
1595
        # protocol.call_with_upload should encode the readv array and then
1596
        # length-prefix the bytes onto the wire.
1597
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
1598
        input = StringIO("\n")
1599
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1600
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1601
        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
1602
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1603
        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.
1604
        self.assertEqual(expected_bytes, output.getvalue())
1605
1606
    def test_client_read_body_bytes_all(self):
1607
        # read_body_bytes should decode the body bytes from the wire into
1608
        # a response.
1609
        expected_bytes = "1234567"
1610
        server_bytes = "ok\n7\n1234567done\n"
1611
        input = StringIO(server_bytes)
1612
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1613
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1614
        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
1615
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1616
        smart_protocol.call('foo')
1617
        smart_protocol.read_response_tuple(True)
1618
        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.
1619
1620
    def test_client_read_body_bytes_incremental(self):
1621
        # test reading a few bytes at a time from the body
1622
        # 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.
1623
        # 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.
1624
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1625
        # that.
1626
        expected_bytes = "1234567"
1627
        server_bytes = "ok\n7\n1234567done\n"
1628
        input = StringIO(server_bytes)
1629
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1630
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1631
        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
1632
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1633
        smart_protocol.call('foo')
1634
        smart_protocol.read_response_tuple(True)
1635
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1636
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1637
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1638
        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.
1639
1640
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1641
        # cancelling the expected body needs to finish the request, but not
1642
        # read any more bytes.
1643
        expected_bytes = "1234567"
1644
        server_bytes = "ok\n7\n1234567done\n"
1645
        input = StringIO(server_bytes)
1646
        output = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1647
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1648
        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
1649
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1650
        smart_protocol.call('foo')
1651
        smart_protocol.read_response_tuple(True)
1652
        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.
1653
        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
1654
        self.assertRaises(
1655
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1656
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1657
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.
1658
class TestSmartProtocolTwo(TestSmartProtocol, CommonSmartProtocolTestMixin):
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1659
    """Tests for the smart protocol version two.
1660
1661
    This test case is mostly the same as TestSmartProtocolOne.
1662
    """
1663
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1664
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
1665
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1666
1667
    def test_construct_version_two_server_protocol(self):
1668
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
1669
        self.assertEqual('', smart_protocol.excess_buffer)
1670
        self.assertEqual('', smart_protocol.in_buffer)
1671
        self.assertFalse(smart_protocol.has_dispatched)
1672
        self.assertEqual(1, smart_protocol.next_read_size())
1673
1674
    def test_construct_version_two_client_protocol(self):
1675
        # we can construct a client protocol from a client medium request
1676
        output = StringIO()
1677
        client_medium = medium.SmartSimplePipesClientMedium(None, output)
1678
        request = client_medium.get_request()
1679
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1680
1681
    def test_server_offset_serialisation(self):
1682
        """The Smart protocol serialises offsets as a comma and \n string.
1683
1684
        We check a number of boundary cases are as expected: empty, one offset,
1685
        one with the order of reads not increasing (an out of order read), and
1686
        one that should coalesce.
1687
        """
1688
        self.assertOffsetSerialisation([], '', self.client_protocol)
1689
        self.assertOffsetSerialisation([(1,2)], '1,2', self.client_protocol)
1690
        self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
1691
            self.client_protocol)
1692
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
1693
            '1,2\n3,4\n100,200', self.client_protocol)
1694
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1695
    def assertBodyStreamSerialisation(self, expected_serialisation,
1696
                                      body_stream):
1697
        """Assert that body_stream is serialised as expected_serialisation."""
1698
        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.
1699
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
1700
        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.
1701
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.
1702
    def assertBodyStreamRoundTrips(self, body_stream):
1703
        """Assert that body_stream is the same after being serialised and
1704
        deserialised.
1705
        """
1706
        out_stream = StringIO()
1707
        protocol._send_stream(body_stream, out_stream.write)
1708
        decoder = protocol.ChunkedBodyDecoder()
1709
        decoder.accept_bytes(out_stream.getvalue())
1710
        decoded_stream = list(iter(decoder.read_next_chunk, None))
1711
        self.assertEqual(body_stream, decoded_stream)
1712
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1713
    def test_body_stream_serialisation_empty(self):
1714
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1715
        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.
1716
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1717
1718
    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.
1719
        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.
1720
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1721
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
1722
            '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.
1723
            stream)
1724
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1725
1726
    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.
1727
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1728
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
1729
        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.
1730
        """
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.
1731
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
1732
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1733
            '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.
1734
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1735
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1736
    def test_body_stream_error_serialistion(self):
1737
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
1738
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1739
                      ('FailureName', 'failure arg'))]
1740
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1741
            '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.
1742
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
1743
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1744
        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.
1745
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
1746
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1747
    def test_accept_bytes_of_bad_request_to_protocol(self):
1748
        out_stream = StringIO()
1749
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1750
            None, out_stream.write)
1751
        smart_protocol.accept_bytes('abc')
1752
        self.assertEqual('abc', smart_protocol.in_buffer)
1753
        smart_protocol.accept_bytes('\n')
1754
        self.assertEqual(
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1755
            protocol.RESPONSE_VERSION_TWO +
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1756
            "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.
1757
            out_stream.getvalue())
1758
        self.assertTrue(smart_protocol.has_dispatched)
1759
        self.assertEqual(0, smart_protocol.next_read_size())
1760
1761
    def test_accept_body_bytes_to_protocol(self):
1762
        protocol = self.build_protocol_waiting_for_body()
1763
        self.assertEqual(6, protocol.next_read_size())
1764
        protocol.accept_bytes('7\nabc')
1765
        self.assertEqual(9, protocol.next_read_size())
1766
        protocol.accept_bytes('defgd')
1767
        protocol.accept_bytes('one\n')
1768
        self.assertEqual(0, protocol.next_read_size())
1769
        self.assertTrue(self.end_received)
1770
1771
    def test_accept_request_and_body_all_at_once(self):
1772
        self._captureVar('BZR_NO_SMART_VFS', None)
1773
        mem_transport = memory.MemoryTransport()
1774
        mem_transport.put_bytes('foo', 'abcdefghij')
1775
        out_stream = StringIO()
1776
        smart_protocol = protocol.SmartServerRequestProtocolTwo(mem_transport,
1777
                out_stream.write)
1778
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1779
        self.assertEqual(0, smart_protocol.next_read_size())
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1780
        self.assertEqual(protocol.RESPONSE_VERSION_TWO +
1781
                         '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.
1782
                         out_stream.getvalue())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1783
        self.assertEqual('', smart_protocol.excess_buffer)
1784
        self.assertEqual('', smart_protocol.in_buffer)
1785
1786
    def test_accept_excess_bytes_are_preserved(self):
1787
        out_stream = StringIO()
1788
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1789
            None, out_stream.write)
1790
        smart_protocol.accept_bytes('hello\nhello\n')
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1791
        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.
1792
                         out_stream.getvalue())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1793
        self.assertEqual("hello\n", smart_protocol.excess_buffer)
1794
        self.assertEqual("", smart_protocol.in_buffer)
1795
1796
    def test_accept_excess_bytes_after_body(self):
1797
        # 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.
1798
        server_protocol = self.build_protocol_waiting_for_body()
1799
        server_protocol.accept_bytes(
1800
            '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.
1801
        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.
1802
        self.assertEqual(protocol.RESPONSE_VERSION_TWO,
1803
                         server_protocol.excess_buffer)
1804
        self.assertEqual("", server_protocol.in_buffer)
1805
        server_protocol.accept_bytes('Y')
1806
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + "Y",
1807
                         server_protocol.excess_buffer)
1808
        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.
1809
1810
    def test_accept_excess_bytes_after_dispatch(self):
1811
        out_stream = StringIO()
1812
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1813
            None, out_stream.write)
1814
        smart_protocol.accept_bytes('hello\n')
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1815
        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.
1816
                         out_stream.getvalue())
1817
        smart_protocol.accept_bytes(protocol.REQUEST_VERSION_TWO + 'hel')
1818
        self.assertEqual(protocol.REQUEST_VERSION_TWO + "hel",
1819
                         smart_protocol.excess_buffer)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1820
        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.
1821
        self.assertEqual(protocol.REQUEST_VERSION_TWO + "hello\n",
1822
                         smart_protocol.excess_buffer)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1823
        self.assertEqual("", smart_protocol.in_buffer)
1824
1825
    def test__send_response_sets_finished_reading(self):
1826
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1827
            None, lambda x: None)
1828
        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.
1829
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1830
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1831
        self.assertEqual(0, smart_protocol.next_read_size())
1832
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1833
    def test__send_response_with_body_stream_sets_finished_reading(self):
1834
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1835
            None, lambda x: None)
1836
        self.assertEqual(1, smart_protocol.next_read_size())
1837
        smart_protocol._send_response(
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
1838
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1839
        self.assertEqual(0, smart_protocol.next_read_size())
1840
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1841
    def test__send_response_errors_with_base_response(self):
1842
        """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.
1843
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1844
            None, lambda x: None)
1845
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1846
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1847
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1848
    def test__send_response_includes_failure_marker(self):
1849
        """FailedSmartServerResponse have 'failed\n' after the version."""
1850
        out_stream = StringIO()
1851
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1852
            None, out_stream.write)
1853
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1854
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
1855
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
1856
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1857
1858
    def test__send_response_includes_success_marker(self):
1859
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
1860
        out_stream = StringIO()
1861
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
1862
            None, out_stream.write)
1863
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1864
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
1865
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
1866
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1867
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1868
    def test_query_version(self):
1869
        """query_version on a SmartClientProtocolTwo should return a number.
1870
        
1871
        The protocol provides the query_version because the domain level clients
1872
        may all need to be able to probe for capabilities.
1873
        """
1874
        # What we really want to test here is that SmartClientProtocolTwo calls
1875
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1876
        # response of tuple-encoded (ok, 1).  Also, seperately we should test
1877
        # 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.
1878
        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.
1879
        output = StringIO()
1880
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1881
        request = client_medium.get_request()
1882
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1883
        self.assertEqual(2, smart_protocol.query_version())
1884
1885
    def test_client_call_empty_response(self):
1886
        # protocol.call() can get back an empty tuple as a response. This occurs
1887
        # when the parsed line is an empty line, and results in a tuple with
1888
        # 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.
1889
        self.assertServerToClientEncoding(
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1890
            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.
1891
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1892
    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.
1893
        # protocol.call() can get back tuples of other lengths. A three element
1894
        # 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.
1895
        self.assertServerToClientEncoding(
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1896
            protocol.RESPONSE_VERSION_TWO + 'success\na\x01b\x0134\n',
1897
            ('a', 'b', '34'),
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1898
            [('a', 'b', '34')])
1899
1900
    def test_client_call_with_body_bytes_uploads(self):
1901
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
1902
        # wire.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
1903
        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.
1904
        input = StringIO("\n")
1905
        output = StringIO()
1906
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1907
        request = client_medium.get_request()
1908
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1909
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1910
        self.assertEqual(expected_bytes, output.getvalue())
1911
1912
    def test_client_call_with_body_readv_array(self):
1913
        # protocol.call_with_upload should encode the readv array and then
1914
        # 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.
1915
        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.
1916
        input = StringIO("\n")
1917
        output = StringIO()
1918
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1919
        request = client_medium.get_request()
1920
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1921
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1922
        self.assertEqual(expected_bytes, output.getvalue())
1923
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
1924
    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.
1925
        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.
1926
        input = StringIO(server_bytes)
1927
        output = StringIO()
1928
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1929
        request = client_medium.get_request()
1930
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1931
        smart_protocol.call('foo')
1932
        smart_protocol.read_response_tuple(False)
1933
        self.assertEqual(True, smart_protocol.response_status)
1934
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1935
    def test_client_read_body_bytes_all(self):
1936
        # read_body_bytes should decode the body bytes from the wire into
1937
        # a response.
1938
        expected_bytes = "1234567"
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1939
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
1940
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1941
        input = StringIO(server_bytes)
1942
        output = StringIO()
1943
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1944
        request = client_medium.get_request()
1945
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1946
        smart_protocol.call('foo')
1947
        smart_protocol.read_response_tuple(True)
1948
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
1949
1950
    def test_client_read_body_bytes_incremental(self):
1951
        # test reading a few bytes at a time from the body
1952
        # XXX: possibly we should test dribbling the bytes into the stringio
1953
        # to make the state machine work harder: however, as we use the
1954
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1955
        # that.
1956
        expected_bytes = "1234567"
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1957
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
1958
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1959
        input = StringIO(server_bytes)
1960
        output = StringIO()
1961
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1962
        request = client_medium.get_request()
1963
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1964
        smart_protocol.call('foo')
1965
        smart_protocol.read_response_tuple(True)
1966
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1967
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1968
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1969
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
1970
1971
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1972
        # cancelling the expected body needs to finish the request, but not
1973
        # read any more bytes.
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1974
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
1975
                        "success\nok\n7\n1234567done\n")
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1976
        input = StringIO(server_bytes)
1977
        output = StringIO()
1978
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1979
        request = client_medium.get_request()
1980
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
1981
        smart_protocol.call('foo')
1982
        smart_protocol.read_response_tuple(True)
1983
        smart_protocol.cancel_read_body()
2432.3.5 by Andrew Bennetts
Merge Robert's status prefix changes to protocol 2.
1984
        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.
1985
                         input.tell())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1986
        self.assertRaises(
1987
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1988
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1989
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1990
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1991
        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.
1992
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1993
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
1994
                        "success\nok\n" + body_header + two_body_chunks +
1995
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
1996
        input = StringIO(server_bytes)
1997
        output = StringIO()
1998
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
1999
        request = client_medium.get_request()
2000
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2001
        smart_protocol.call('foo')
2002
        smart_protocol.read_response_tuple(True)
2003
        stream = smart_protocol.read_streamed_body()
2004
        self.assertEqual(['1234', '567'], list(stream))
2005
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2006
    def test_read_streamed_body_error(self):
2007
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2008
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2009
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2010
        err_signal = 'ERR\n'
2011
        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.
2012
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2013
        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.
2014
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2015
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2016
        input = StringIO(server_bytes)
2017
        output = StringIO()
2018
        client_medium = medium.SmartSimplePipesClientMedium(input, output)
2019
        smart_request = client_medium.get_request()
2020
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2021
        smart_protocol.call('foo')
2022
        smart_protocol.read_response_tuple(True)
2023
        expected_chunks = [
2024
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2025
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2026
        stream = smart_protocol.read_streamed_body()
2027
        self.assertEqual(expected_chunks, list(stream))
2028
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2029
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.
2030
class TestSmartClientUnicode(tests.TestCase):
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2031
    """_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.
2032
2033
    Unicode arguments to call_with_body_bytes are not correct (remote method
2034
    names, arguments, and bodies must all be expressed as byte strings), but
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2035
    _SmartClient should gracefully reject them, rather than getting into a
2036
    broken state that prevents future correct calls from working.  That is, it
2037
    should be possible to issue more requests on the medium afterwards, rather
2038
    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.
2039
    mysteriously fail with TooManyConcurrentRequests.
2040
    """
2041
2042
    def assertCallDoesNotBreakMedium(self, method, args, body):
2043
        """Call a medium with the given method, args and body, then assert that
2044
        the medium is left in a sane state, i.e. is capable of allowing further
2045
        requests.
2046
        """
2047
        input = StringIO("\n")
2048
        output = StringIO()
2049
        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.
2050
        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.
2051
        self.assertRaises(TypeError,
2052
            smart_client.call_with_body_bytes, method, args, body)
2053
        self.assertEqual("", output.getvalue())
2054
        self.assertEqual(None, client_medium._current_request)
2055
2056
    def test_call_with_body_bytes_unicode_method(self):
2057
        self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
2058
2059
    def test_call_with_body_bytes_unicode_args(self):
2060
        self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
2414.1.2 by Andrew Bennetts
Deal with review comments.
2061
        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.
2062
2063
    def test_call_with_body_bytes_unicode_body(self):
2064
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
2065
2066
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2067
class LengthPrefixedBodyDecoder(tests.TestCase):
2068
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2069
    # XXX: TODO: make accept_reading_trailer invoke translate_response or 
2070
    # something similar to the ProtocolBase method.
2071
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2072
    def test_construct(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2073
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2074
        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.
2075
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2076
        self.assertEqual('', decoder.read_pending_data())
2077
        self.assertEqual('', decoder.unused_data)
2078
2079
    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
2080
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2081
        decoder.accept_bytes('')
2082
        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.
2083
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2084
        self.assertEqual('', decoder.read_pending_data())
2085
        self.assertEqual('', decoder.unused_data)
2086
        decoder.accept_bytes('7')
2087
        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.
2088
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2089
        self.assertEqual('', decoder.read_pending_data())
2090
        self.assertEqual('', decoder.unused_data)
2091
        decoder.accept_bytes('\na')
2092
        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.
2093
        self.assertEqual(11, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2094
        self.assertEqual('a', decoder.read_pending_data())
2095
        self.assertEqual('', decoder.unused_data)
2096
        decoder.accept_bytes('bcdefgd')
2097
        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.
2098
        self.assertEqual(4, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2099
        self.assertEqual('bcdefg', decoder.read_pending_data())
2100
        self.assertEqual('', decoder.unused_data)
2101
        decoder.accept_bytes('one')
2102
        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.
2103
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2104
        self.assertEqual('', decoder.read_pending_data())
2105
        self.assertEqual('', decoder.unused_data)
2106
        decoder.accept_bytes('\nblarg')
2107
        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.
2108
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2109
        self.assertEqual('', decoder.read_pending_data())
2110
        self.assertEqual('blarg', decoder.unused_data)
2111
        
2112
    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
2113
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2114
        decoder.accept_bytes('1\nadone\nunused')
2115
        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.
2116
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2117
        self.assertEqual('a', decoder.read_pending_data())
2118
        self.assertEqual('unused', decoder.unused_data)
2119
2120
    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
2121
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2122
        decoder.accept_bytes('1\na')
2123
        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.
2124
        self.assertEqual(5, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2125
        self.assertEqual('a', decoder.read_pending_data())
2126
        self.assertEqual('', decoder.unused_data)
2127
        decoder.accept_bytes('done\n')
2128
        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.
2129
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2130
        self.assertEqual('', decoder.read_pending_data())
2131
        self.assertEqual('', decoder.unused_data)
2132
2133
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2134
class TestChunkedBodyDecoder(tests.TestCase):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2135
    """Tests for ChunkedBodyDecoder.
2136
    
2137
    This is the body decoder used for protocol version two.
2138
    """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2139
2140
    def test_construct(self):
2141
        decoder = protocol.ChunkedBodyDecoder()
2142
        self.assertFalse(decoder.finished_reading)
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2143
        self.assertEqual(8, decoder.next_read_size())
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2144
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2145
        self.assertEqual('', decoder.unused_data)
2146
2147
    def test_empty_content(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2148
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
2149
        """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2150
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2151
        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.
2152
        decoder.accept_bytes('END\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2153
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2154
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2155
        self.assertEqual('', decoder.unused_data)
2156
2157
    def test_one_chunk(self):
2158
        """A body in a single chunk is decoded correctly."""
2159
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2160
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2161
        chunk_length = 'f\n'
2162
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2163
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2164
        decoder.accept_bytes(chunk_length + chunk_content + finish)
2165
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2166
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2167
        self.assertEqual('', decoder.unused_data)
2168
        
2169
    def test_incomplete_chunk(self):
2170
        """When there are less bytes in the chunk than declared by the length,
2171
        then we haven't finished reading yet.
2172
        """
2173
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2174
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2175
        chunk_length = '8\n'
2176
        three_bytes = '123'
2177
        decoder.accept_bytes(chunk_length + three_bytes)
2178
        self.assertFalse(decoder.finished_reading)
2179
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2180
            5 + 4, decoder.next_read_size(),
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2181
            "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.
2182
            "this chunk plus 4 (the length of the end-of-body marker: "
2183
            "'END\\n')")
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2184
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2185
2186
    def test_incomplete_length(self):
2187
        """A chunk length hasn't been read until a newline byte has been read.
2188
        """
2189
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2190
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2191
        decoder.accept_bytes('9')
2192
        self.assertEqual(
2193
            1, decoder.next_read_size(),
2194
            "The next_read_size hint should be 1, because we don't know the "
2195
            "length yet.")
2196
        decoder.accept_bytes('\n')
2197
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2198
            9 + 4, decoder.next_read_size(),
2199
            "The next_read_size hint should be the length of the chunk plus 4 "
2200
            "(the length of the end-of-body marker: 'END\\n')")
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2201
        self.assertFalse(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2202
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2203
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2204
    def test_two_chunks(self):
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2205
        """Content from multiple chunks is concatenated."""
2206
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2207
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2208
        chunk_one = '3\naaa'
2209
        chunk_two = '5\nbbbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2210
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2211
        decoder.accept_bytes(chunk_one + chunk_two + finish)
2212
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2213
        self.assertEqual('aaa', decoder.read_next_chunk())
2214
        self.assertEqual('bbbbb', decoder.read_next_chunk())
2215
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2216
        self.assertEqual('', decoder.unused_data)
2217
2218
    def test_excess_bytes(self):
2219
        """Bytes after the chunked body are reported as unused bytes."""
2220
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2221
        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.
2222
        chunked_body = "5\naaaaaEND\n"
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2223
        excess_bytes = "excess bytes"
2224
        decoder.accept_bytes(chunked_body + excess_bytes)
2225
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2226
        self.assertEqual('aaaaa', decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2227
        self.assertEqual(excess_bytes, decoder.unused_data)
2228
        self.assertEqual(
2229
            1, decoder.next_read_size(),
2230
            "next_read_size hint should be 1 when finished_reading.")
2231
2232
    def test_multidigit_length(self):
2233
        """Lengths in the chunk prefixes can have multiple digits."""
2234
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2235
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2236
        length = 0x123
2237
        chunk_prefix = hex(length) + '\n'
2238
        chunk_bytes = 'z' * length
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2239
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2240
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
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(chunk_bytes, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2243
2244
    def test_byte_at_a_time(self):
2245
        """A complete body fed to the decoder one byte at a time should not
2246
        confuse the decoder.  That is, it should give the same result as if the
2247
        bytes had been received in one batch.
2248
2249
        This test is the same as test_one_chunk apart from the way accept_bytes
2250
        is called.
2251
        """
2252
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2253
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2254
        chunk_length = 'f\n'
2255
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2256
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2257
        for byte in (chunk_length + chunk_content + finish):
2258
            decoder.accept_bytes(byte)
2259
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2260
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2261
        self.assertEqual('', decoder.unused_data)
2262
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2263
    def test_read_pending_data_resets(self):
2264
        """read_pending_data does not return the same bytes twice."""
2265
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2266
        decoder.accept_bytes('chunked\n')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2267
        chunk_one = '3\naaa'
2268
        chunk_two = '3\nbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2269
        finish = 'END\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2270
        decoder.accept_bytes(chunk_one)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2271
        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.
2272
        decoder.accept_bytes(chunk_two)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2273
        self.assertEqual('bbb', decoder.read_next_chunk())
2274
        self.assertEqual(None, decoder.read_next_chunk())
2275
2276
    def test_decode_error(self):
2277
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2278
        decoder.accept_bytes('chunked\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2279
        chunk_one = 'b\nfirst chunk'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2280
        error_signal = 'ERR\n'
2281
        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.
2282
        finish = 'END\n'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2283
        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.
2284
        self.assertTrue(decoder.finished_reading)
2285
        self.assertEqual('first chunk', decoder.read_next_chunk())
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2286
        expected_failure = _mod_request.FailedSmartServerResponse(
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2287
            ('part1', 'part2'))
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2288
        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.
2289
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2290
    def test_bad_header(self):
2291
        """accept_bytes raises a SmartProtocolError if a chunked body does not
2292
        start with the right header.
2293
        """
2294
        decoder = protocol.ChunkedBodyDecoder()
2295
        self.assertRaises(
2296
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
2297
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
2298
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2299
class TestSuccessfulSmartServerResponse(tests.TestCase):
2300
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2301
    def test_construct_no_body(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2302
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2303
        self.assertEqual(('foo', 'bar'), response.args)
2304
        self.assertEqual(None, response.body)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2305
2306
    def test_construct_with_body(self):
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2307
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'),
2308
                                                              'bytes')
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2309
        self.assertEqual(('foo', 'bar'), response.args)
2310
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
2311
        # repr(response) doesn't trigger exceptions.
2312
        repr(response)
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2313
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2314
    def test_construct_with_body_stream(self):
2315
        bytes_iterable = ['abc']
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2316
        response = _mod_request.SuccessfulSmartServerResponse(
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2317
            ('foo', 'bar'), body_stream=bytes_iterable)
2318
        self.assertEqual(('foo', 'bar'), response.args)
2319
        self.assertEqual(bytes_iterable, response.body_stream)
2320
2321
    def test_construct_rejects_body_and_body_stream(self):
2322
        """'body' and 'body_stream' are mutually exclusive."""
2323
        self.assertRaises(
2324
            errors.BzrError,
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2325
            _mod_request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2326
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2327
    def test_is_successful(self):
2328
        """is_successful should return True for SuccessfulSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2329
        response = _mod_request.SuccessfulSmartServerResponse(('error',))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2330
        self.assertEqual(True, response.is_successful())
2331
2332
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2333
class TestFailedSmartServerResponse(tests.TestCase):
2334
2335
    def test_construct(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2336
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2337
        self.assertEqual(('foo', 'bar'), response.args)
2338
        self.assertEqual(None, response.body)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2339
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2340
        self.assertEqual(('foo', 'bar'), response.args)
2341
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
2342
        # repr(response) doesn't trigger exceptions.
2343
        repr(response)
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2344
2345
    def test_is_successful(self):
2346
        """is_successful should return False for FailedSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2347
        response = _mod_request.FailedSmartServerResponse(('error',))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
2348
        self.assertEqual(False, response.is_successful())
2349
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
2350
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2351
class FakeHTTPMedium(object):
2352
    def __init__(self):
2353
        self.written_request = None
2354
        self._current_request = None
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
2355
    def send_http_smart_request(self, bytes):
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2356
        self.written_request = bytes
2357
        return None
2358
2359
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
2360
class HTTPTunnellingSmokeTest(tests.TestCase):
2361
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)
2362
    def setUp(self):
2363
        super(HTTPTunnellingSmokeTest, self).setUp()
2364
        # We use the VFS layer as part of HTTP tunnelling tests.
2402.1.2 by Andrew Bennetts
Deal with review comments.
2365
        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)
2366
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2367
    def test_smart_http_medium_request_accept_bytes(self):
2368
        medium = FakeHTTPMedium()
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
2369
        request = SmartClientHTTPMediumRequest(medium)
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
2370
        request.accept_bytes('abc')
2371
        request.accept_bytes('def')
2372
        self.assertEqual(None, medium.written_request)
2373
        request.finished_writing()
2374
        self.assertEqual('abcdef', medium.written_request)
2375
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.
2376
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2377
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.
2378
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
2379
    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.
2380
        # 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')).
2381
        # requests for child URLs of that to the original URL.  i.e., we want to
2382
        # POST to "bzr+http://host/foo/.bzr/smart" and never something like
2383
        # "bzr+http://host/foo/.bzr/branch/.bzr/smart".  So, a cloned
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2384
        # 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.
2385
        # it sends in smart requests accordingly.
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
2386
        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.
2387
        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')).
2388
        self.assertEqual(base_transport._http_transport,
2389
                         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.
2390
        self.assertEqual('child_dir/foo', new_transport._remote_path('foo'))
2391
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
2392
    def test_remote_path_unnormal_base(self):
2393
        # If the transport's base isn't normalised, the _remote_path should
2394
        # still be calculated correctly.
2395
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
2396
        self.assertEqual('c', base_transport._remote_path('c'))
2397
2398
    def test_clone_unnormal_base(self):
2399
        # If the transport's base isn't normalised, cloned transports should
2400
        # still work correctly.
2401
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
2402
        new_transport = base_transport.clone('c')
2403
        self.assertEqual('bzr+http://host/%7Ea/b/c/', new_transport.base)
2404
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2405
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
2406
# TODO: Client feature that does get_bundle and then installs that into a
2407
# branch; this can be used in place of the regular pull/fetch operation when
2408
# coming from a smart server.
2409
#
2410
# TODO: Eventually, want to do a 'branch' command by fetching the whole
2411
# history as one big bundle.  How?  
2412
#
2413
# The branch command does 'br_from.sprout', which tries to preserve the same
2414
# format.  We don't necessarily even want that.  
2415
#
2416
# It might be simpler to handle cmd_pull first, which does a simpler fetch()
2417
# operation from one branch into another.  It already has some code for
2418
# pulling from a bundle, which it does by trying to see if the destination is
2419
# a bundle file.  So it seems the logic for pull ought to be:
2420
# 
2421
#  - if it's a smart server, get a bundle from there and install that
2422
#  - if it's a bundle, install that
2423
#  - if it's a branch, pull from there
2424
#
2425
# Getting a bundle from a smart server is a bit different from reading a
2426
# bundle from a URL:
2427
#
2428
#  - we can reasonably remember the URL we last read from 
2429
#  - you can specify a revision number to pull, and we need to pass it across
2430
#    to the server as a limit on what will be requested
2431
#
2432
# TODO: Given a URL, determine whether it is a smart server or not (or perhaps
2433
# otherwise whether it's a bundle?)  Should this be a property or method of
2434
# the transport?  For the ssh protocol, we always know it's a smart server.
2435
# For http, we potentially need to probe.  But if we're explicitly given
2436
# bzr+http:// then we can skip that for now.