/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
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
24
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
25
import bzrlib
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,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
36
        message,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
37
        protocol,
2432.4.3 by Robert Collins
Refactor the HPSS Response code to take SmartServerResponse rather than args and body.
38
        request as _mod_request,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
39
        server,
40
        vfs,
41
)
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
42
from bzrlib.tests.test_smart import TestCaseWithSmartMedium
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
43
from bzrlib.transport import (
44
        get_transport,
45
        local,
46
        memory,
2400.1.1 by Andrew Bennetts
Rename bzrlib/transport/smart.py to bzrlib/transport/remote.py.
47
        remote,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
48
        )
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
49
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
50
51
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
52
class StringIOSSHVendor(object):
53
    """A SSH vendor that uses StringIO to buffer writes and answer reads."""
54
55
    def __init__(self, read_from, write_to):
56
        self.read_from = read_from
57
        self.write_to = write_to
58
        self.calls = []
59
60
    def connect_ssh(self, username, password, host, port, command):
61
        self.calls.append(('connect_ssh', username, password, host, port,
62
            command))
63
        return StringIOSSHConnection(self)
64
65
66
class StringIOSSHConnection(object):
67
    """A SSH connection that uses StringIO to buffer writes and answer reads."""
68
69
    def __init__(self, vendor):
70
        self.vendor = vendor
71
    
72
    def close(self):
73
        self.vendor.calls.append(('close', ))
74
        
75
    def get_filelike_channels(self):
76
        return self.vendor.read_from, self.vendor.write_to
77
78
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
79
class _InvalidHostnameFeature(tests.Feature):
80
    """Does 'non_existent.invalid' fail to resolve?
81
    
82
    RFC 2606 states that .invalid is reserved for invalid domain names, and
83
    also underscores are not a valid character in domain names.  Despite this,
84
    it's possible a badly misconfigured name server might decide to always
85
    return an address for any name, so this feature allows us to distinguish a
86
    broken system from a broken test.
87
    """
88
89
    def _probe(self):
90
        try:
91
            socket.gethostbyname('non_existent.invalid')
92
        except socket.gaierror:
93
            # The host name failed to resolve.  Good.
94
            return True
95
        else:
96
            return False
97
98
    def feature_name(self):
99
        return 'invalid hostname'
100
101
InvalidHostnameFeature = _InvalidHostnameFeature()
102
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
103
104
class SmartClientMediumTests(tests.TestCase):
105
    """Tests for SmartClientMedium.
106
107
    We should create a test scenario for this: we need a server module that
108
    construct the test-servers (like make_loopsocket_and_medium), and the list
109
    of SmartClientMedium classes to test.
110
    """
111
112
    def make_loopsocket_and_medium(self):
113
        """Create a loopback socket for testing, and a medium aimed at it."""
114
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
115
        sock.bind(('127.0.0.1', 0))
116
        sock.listen(1)
117
        port = sock.getsockname()[1]
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
118
        client_medium = medium.SmartTCPClientMedium('127.0.0.1', port, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
119
        return sock, client_medium
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
120
121
    def receive_bytes_on_server(self, sock, bytes):
122
        """Accept a connection on sock and read 3 bytes.
123
124
        The bytes are appended to the list bytes.
125
126
        :return: a Thread which is running to do the accept and recv.
127
        """
128
        def _receive_bytes_on_server():
129
            connection, address = sock.accept()
2091.1.1 by Martin Pool
Avoid MSG_WAITALL as it doesn't work on Windows
130
            bytes.append(osutils.recv_all(connection, 3))
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
131
            connection.close()
132
        t = threading.Thread(target=_receive_bytes_on_server)
133
        t.start()
134
        return t
135
    
136
    def test_construct_smart_simple_pipes_client_medium(self):
137
        # the SimplePipes client medium takes two pipes:
138
        # readable pipe, writeable pipe.
139
        # Constructing one should just save these and do nothing.
140
        # We test this by passing in None.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
141
        client_medium = medium.SmartSimplePipesClientMedium(None, None, None)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
142
        
143
    def test_simple_pipes_client_request_type(self):
144
        # SimplePipesClient should use SmartClientStreamMediumRequest's.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
145
        client_medium = medium.SmartSimplePipesClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
146
        request = client_medium.get_request()
147
        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.
148
149
    def test_simple_pipes_client_get_concurrent_requests(self):
150
        # the simple_pipes client does not support pipelined requests:
151
        # but it does support serial requests: we construct one after 
152
        # another is finished. This is a smoke test testing the integration
153
        # of the SmartClientStreamMediumRequest and the SmartClientStreamMedium
154
        # classes - as the sibling classes share this logic, they do not have
155
        # explicit tests for this.
156
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
157
        client_medium = medium.SmartSimplePipesClientMedium(
158
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
159
        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.
160
        request.finished_writing()
161
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
162
        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.
163
        request2.finished_writing()
164
        request2.finished_reading()
165
166
    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.
167
        # accept_bytes writes to the writeable pipe.
168
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
169
        client_medium = medium.SmartSimplePipesClientMedium(
170
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
171
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
172
        self.assertEqual('abc', output.getvalue())
173
    
174
    def test_simple_pipes_client_disconnect_does_nothing(self):
175
        # calling disconnect does nothing.
176
        input = StringIO()
177
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
178
        client_medium = medium.SmartSimplePipesClientMedium(
179
            input, output, 'base')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
180
        # send some bytes to ensure disconnecting after activity still does not
181
        # close.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
182
        client_medium._accept_bytes('abc')
183
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
184
        self.assertFalse(input.closed)
185
        self.assertFalse(output.closed)
186
187
    def test_simple_pipes_client_accept_bytes_after_disconnect(self):
188
        # calling disconnect on the client does not alter the pipe that
189
        # accept_bytes writes to.
190
        input = StringIO()
191
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
192
        client_medium = medium.SmartSimplePipesClientMedium(
193
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
194
        client_medium._accept_bytes('abc')
195
        client_medium.disconnect()
196
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
197
        self.assertFalse(input.closed)
198
        self.assertFalse(output.closed)
199
        self.assertEqual('abcabc', output.getvalue())
200
    
201
    def test_simple_pipes_client_ignores_disconnect_when_not_connected(self):
202
        # Doing a disconnect on a new (and thus unconnected) SimplePipes medium
203
        # does nothing.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
204
        client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
205
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
206
207
    def test_simple_pipes_client_can_always_read(self):
208
        # SmartSimplePipesClientMedium is never disconnected, so read_bytes
209
        # always tries to read from the underlying pipe.
210
        input = StringIO('abcdef')
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
211
        client_medium = medium.SmartSimplePipesClientMedium(input, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
212
        self.assertEqual('abc', client_medium.read_bytes(3))
213
        client_medium.disconnect()
214
        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.
215
        
216
    def test_simple_pipes_client_supports__flush(self):
217
        # invoking _flush on a SimplePipesClient should flush the output 
218
        # pipe. We test this by creating an output pipe that records
219
        # flush calls made to it.
220
        from StringIO import StringIO # get regular StringIO
221
        input = StringIO()
222
        output = StringIO()
223
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
224
        def logging_flush(): flush_calls.append('flush')
225
        output.flush = logging_flush
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
226
        client_medium = medium.SmartSimplePipesClientMedium(
227
            input, output, 'base')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
228
        # this call is here to ensure we only flush once, not on every
229
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
230
        client_medium._accept_bytes('abc')
231
        client_medium._flush()
232
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
233
        self.assertEqual(['flush'], flush_calls)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
234
235
    def test_construct_smart_ssh_client_medium(self):
236
        # the SSH client medium takes:
237
        # host, port, username, password, vendor
238
        # Constructing one should just save these and do nothing.
239
        # we test this by creating a empty bound socket and constructing
240
        # a medium.
241
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
242
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
243
        unopened_port = sock.getsockname()[1]
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
244
        # having vendor be invalid means that if it tries to connect via the
245
        # vendor it will blow up.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
246
        client_medium = medium.SmartSSHClientMedium('127.0.0.1', unopened_port,
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
247
            username=None, password=None, base='base', vendor="not a vendor",
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
248
            bzr_remote_path='bzr')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
249
        sock.close()
250
251
    def test_ssh_client_connects_on_first_use(self):
252
        # The only thing that initiates a connection from the medium is giving
253
        # it bytes.
254
        output = StringIO()
255
        vendor = StringIOSSHVendor(StringIO(), output)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
256
        client_medium = medium.SmartSSHClientMedium(
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
257
            'a hostname', 'a port', 'a username', 'a password', 'base', vendor,
258
            'bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
259
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
260
        self.assertEqual('abc', output.getvalue())
261
        self.assertEqual([('connect_ssh', 'a username', 'a password',
262
            'a hostname', 'a port',
263
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes'])],
264
            vendor.calls)
265
    
266
    def test_ssh_client_changes_command_when_BZR_REMOTE_PATH_is_set(self):
267
        # The only thing that initiates a connection from the medium is giving
268
        # it bytes.
269
        output = StringIO()
270
        vendor = StringIOSSHVendor(StringIO(), output)
271
        orig_bzr_remote_path = os.environ.get('BZR_REMOTE_PATH')
272
        def cleanup_environ():
273
            osutils.set_or_unset_env('BZR_REMOTE_PATH', orig_bzr_remote_path)
274
        self.addCleanup(cleanup_environ)
275
        os.environ['BZR_REMOTE_PATH'] = 'fugly'
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
276
        client_medium = self.callDeprecated(
277
            ['bzr_remote_path is required as of bzr 0.92'],
278
            medium.SmartSSHClientMedium, 'a hostname', 'a port', 'a username',
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
279
            'a password', 'base', vendor)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
280
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
281
        self.assertEqual('abc', output.getvalue())
282
        self.assertEqual([('connect_ssh', 'a username', 'a password',
283
            'a hostname', 'a port',
284
            ['fugly', 'serve', '--inet', '--directory=/', '--allow-writes'])],
285
            vendor.calls)
286
    
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
287
    def test_ssh_client_changes_command_when_bzr_remote_path_passed(self):
288
        # The only thing that initiates a connection from the medium is giving
289
        # it bytes.
290
        output = StringIO()
291
        vendor = StringIOSSHVendor(StringIO(), output)
292
        client_medium = medium.SmartSSHClientMedium('a hostname', 'a port',
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
293
            'a username', 'a password', 'base', vendor, bzr_remote_path='fugly')
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
294
        client_medium._accept_bytes('abc')
295
        self.assertEqual('abc', output.getvalue())
296
        self.assertEqual([('connect_ssh', 'a username', 'a password',
297
            'a hostname', 'a port',
298
            ['fugly', 'serve', '--inet', '--directory=/', '--allow-writes'])],
299
            vendor.calls)
300
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
301
    def test_ssh_client_disconnect_does_so(self):
302
        # calling disconnect should disconnect both the read_from and write_to
303
        # file-like object it from the ssh connection.
304
        input = StringIO()
305
        output = StringIO()
306
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
307
        client_medium = medium.SmartSSHClientMedium(
308
            'a hostname', base='base', vendor=vendor, bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
309
        client_medium._accept_bytes('abc')
310
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
311
        self.assertTrue(input.closed)
312
        self.assertTrue(output.closed)
313
        self.assertEqual([
314
            ('connect_ssh', None, None, 'a hostname', None,
315
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
316
            ('close', ),
317
            ],
318
            vendor.calls)
319
320
    def test_ssh_client_disconnect_allows_reconnection(self):
321
        # calling disconnect on the client terminates the connection, but should
322
        # not prevent additional connections occuring.
323
        # we test this by initiating a second connection after doing a
324
        # disconnect.
325
        input = StringIO()
326
        output = StringIO()
327
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
328
        client_medium = medium.SmartSSHClientMedium(
329
            'a hostname', base='base', vendor=vendor, bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
330
        client_medium._accept_bytes('abc')
331
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
332
        # the disconnect has closed output, so we need a new output for the
333
        # new connection to write to.
334
        input2 = StringIO()
335
        output2 = StringIO()
336
        vendor.read_from = input2
337
        vendor.write_to = output2
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
338
        client_medium._accept_bytes('abc')
339
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
340
        self.assertTrue(input.closed)
341
        self.assertTrue(output.closed)
342
        self.assertTrue(input2.closed)
343
        self.assertTrue(output2.closed)
344
        self.assertEqual([
345
            ('connect_ssh', None, None, 'a hostname', None,
346
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
347
            ('close', ),
348
            ('connect_ssh', None, None, 'a hostname', None,
349
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
350
            ('close', ),
351
            ],
352
            vendor.calls)
353
    
354
    def test_ssh_client_ignores_disconnect_when_not_connected(self):
355
        # 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.
356
        # does not fail.  It's ok to disconnect an unconnected medium.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
357
        client_medium = medium.SmartSSHClientMedium(
358
            None, base='base', bzr_remote_path='bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
359
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
360
361
    def test_ssh_client_raises_on_read_when_not_connected(self):
362
        # 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.
363
        # MediumNotConnected.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
364
        client_medium = medium.SmartSSHClientMedium(
365
            None, base='base', bzr_remote_path='bzr')
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
366
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
367
                          0)
368
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
369
                          1)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
370
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
371
    def test_ssh_client_supports__flush(self):
372
        # invoking _flush on a SSHClientMedium should flush the output 
373
        # pipe. We test this by creating an output pipe that records
374
        # flush calls made to it.
375
        from StringIO import StringIO # get regular StringIO
376
        input = StringIO()
377
        output = StringIO()
378
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
379
        def logging_flush(): flush_calls.append('flush')
380
        output.flush = logging_flush
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
381
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
382
        client_medium = medium.SmartSSHClientMedium(
383
            'a hostname', base='base', vendor=vendor, bzr_remote_path='bzr')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
384
        # this call is here to ensure we only flush once, not on every
385
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
386
        client_medium._accept_bytes('abc')
387
        client_medium._flush()
388
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
389
        self.assertEqual(['flush'], flush_calls)
390
        
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
391
    def test_construct_smart_tcp_client_medium(self):
392
        # the TCP client medium takes a host and a port.  Constructing it won't
393
        # connect to anything.
394
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
395
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
396
        unopened_port = sock.getsockname()[1]
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
397
        client_medium = medium.SmartTCPClientMedium(
398
            '127.0.0.1', unopened_port, 'base')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
399
        sock.close()
400
401
    def test_tcp_client_connects_on_first_use(self):
402
        # The only thing that initiates a connection from the medium is giving
403
        # it bytes.
404
        sock, medium = self.make_loopsocket_and_medium()
405
        bytes = []
406
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
407
        medium.accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
408
        t.join()
409
        sock.close()
410
        self.assertEqual(['abc'], bytes)
411
    
412
    def test_tcp_client_disconnect_does_so(self):
413
        # calling disconnect on the client terminates the connection.
414
        # 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.
415
        # 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.
416
        sock, medium = self.make_loopsocket_and_medium()
417
        bytes = []
418
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
419
        medium.accept_bytes('ab')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
420
        medium.disconnect()
421
        t.join()
422
        sock.close()
423
        self.assertEqual(['ab'], bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
424
        # 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.
425
        # really did disconnect.
426
        medium.disconnect()
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
427
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
428
    
429
    def test_tcp_client_ignores_disconnect_when_not_connected(self):
430
        # 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.
431
        # does not fail.  It's ok to disconnect an unconnected medium.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
432
        client_medium = medium.SmartTCPClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
433
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
434
435
    def test_tcp_client_raises_on_read_when_not_connected(self):
436
        # 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.
437
        # MediumNotConnected.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
438
        client_medium = medium.SmartTCPClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
439
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 0)
440
        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.
441
442
    def test_tcp_client_supports__flush(self):
443
        # invoking _flush on a TCPClientMedium should do something useful.
444
        # RBC 20060922 not sure how to test/tell in this case.
445
        sock, medium = self.make_loopsocket_and_medium()
446
        bytes = []
447
        t = self.receive_bytes_on_server(sock, bytes)
448
        # try with nothing buffered
449
        medium._flush()
450
        medium._accept_bytes('ab')
451
        # and with something sent.
452
        medium._flush()
453
        medium.disconnect()
454
        t.join()
455
        sock.close()
456
        self.assertEqual(['ab'], bytes)
457
        # now disconnect again : this should not do anything, if disconnection
458
        # really did disconnect.
459
        medium.disconnect()
460
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
461
    def test_tcp_client_host_unknown_connection_error(self):
462
        self.requireFeature(InvalidHostnameFeature)
463
        client_medium = medium.SmartTCPClientMedium(
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
464
            'non_existent.invalid', 4155, 'base')
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
465
        self.assertRaises(
466
            errors.ConnectionError, client_medium._ensure_connection)
467
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
468
469
class TestSmartClientStreamMediumRequest(tests.TestCase):
470
    """Tests the for SmartClientStreamMediumRequest.
471
    
472
    SmartClientStreamMediumRequest is a helper for the three stream based 
473
    mediums: TCP, SSH, SimplePipes, so we only test it once, and then test that
474
    those three mediums implement the interface it expects.
475
    """
476
477
    def test_accept_bytes_after_finished_writing_errors(self):
478
        # calling accept_bytes after calling finished_writing raises 
479
        # WritingCompleted to prevent bad assumptions on stream environments
480
        # breaking the needs of message-based environments.
481
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
482
        client_medium = medium.SmartSimplePipesClientMedium(
483
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
484
        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.
485
        request.finished_writing()
486
        self.assertRaises(errors.WritingCompleted, request.accept_bytes, None)
487
488
    def test_accept_bytes(self):
489
        # accept bytes should invoke _accept_bytes on the stream medium.
490
        # we test this by using the SimplePipes medium - the most trivial one
491
        # and checking that the pipes get the data.
492
        input = StringIO()
493
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
494
        client_medium = medium.SmartSimplePipesClientMedium(
495
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
496
        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.
497
        request.accept_bytes('123')
498
        request.finished_writing()
499
        request.finished_reading()
500
        self.assertEqual('', input.getvalue())
501
        self.assertEqual('123', output.getvalue())
502
503
    def test_construct_sets_stream_request(self):
504
        # constructing a SmartClientStreamMediumRequest on a StreamMedium sets
505
        # the current request to the new SmartClientStreamMediumRequest
506
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
507
        client_medium = medium.SmartSimplePipesClientMedium(
508
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
509
        request = medium.SmartClientStreamMediumRequest(client_medium)
510
        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.
511
512
    def test_construct_while_another_request_active_throws(self):
513
        # constructing a SmartClientStreamMediumRequest on a StreamMedium with
514
        # a non-None _current_request raises TooManyConcurrentRequests.
515
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
516
        client_medium = medium.SmartSimplePipesClientMedium(
517
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
518
        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.
519
        self.assertRaises(errors.TooManyConcurrentRequests,
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
520
            medium.SmartClientStreamMediumRequest, client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
521
522
    def test_finished_read_clears_current_request(self):
523
        # calling finished_reading clears the current request from the requests
524
        # medium
525
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
526
        client_medium = medium.SmartSimplePipesClientMedium(
527
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
528
        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.
529
        request.finished_writing()
530
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
531
        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.
532
533
    def test_finished_read_before_finished_write_errors(self):
534
        # calling finished_reading before calling finished_writing triggers a
535
        # WritingNotComplete error.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
536
        client_medium = medium.SmartSimplePipesClientMedium(
537
            None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
538
        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.
539
        self.assertRaises(errors.WritingNotComplete, request.finished_reading)
540
        
541
    def test_read_bytes(self):
542
        # read bytes should invoke _read_bytes on the stream medium.
543
        # we test this by using the SimplePipes medium - the most trivial one
544
        # and checking that the data is supplied. Its possible that a 
545
        # faulty implementation could poke at the pipe variables them selves,
546
        # but we trust that this will be caught as it will break the integration
547
        # smoke tests.
548
        input = StringIO('321')
549
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
550
        client_medium = medium.SmartSimplePipesClientMedium(
551
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
552
        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.
553
        request.finished_writing()
554
        self.assertEqual('321', request.read_bytes(3))
555
        request.finished_reading()
556
        self.assertEqual('', input.read())
557
        self.assertEqual('', output.getvalue())
558
559
    def test_read_bytes_before_finished_write_errors(self):
560
        # calling read_bytes before calling finished_writing triggers a
561
        # WritingNotComplete error because the Smart protocol is designed to be
562
        # compatible with strict message based protocols like HTTP where the
563
        # request cannot be submitted until the writing has completed.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
564
        client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
565
        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.
566
        self.assertRaises(errors.WritingNotComplete, request.read_bytes, None)
567
568
    def test_read_bytes_after_finished_reading_errors(self):
569
        # calling read_bytes after calling finished_reading raises 
570
        # ReadingCompleted to prevent bad assumptions on stream environments
571
        # breaking the needs of message-based environments.
572
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
573
        client_medium = medium.SmartSimplePipesClientMedium(
574
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
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
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
612
        self.unused_data = ''
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
618
            self.unused_data = self.accepted_bytes[len(self.expected_bytes):]
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
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
        
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
735
    def test_socket_stream_incomplete_request(self):
736
        """The medium should still construct the right protocol version even if
737
        the initial read only reads part of the request.
738
739
        Specifically, it should correctly read the protocol version line even
740
        if the partial read doesn't end in a newline.  An older, naive
741
        implementation of _get_line in the server used to have a bug in that
742
        case.
743
        """
744
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
745
        rest_of_request_bytes = 'lo\n'
746
        expected_response = (
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
747
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
748
        server_sock, client_sock = self.portable_socket_pair()
749
        server = medium.SmartServerSocketStreamMedium(
750
            server_sock, None)
751
        client_sock.sendall(incomplete_request_bytes)
752
        server_protocol = server._build_protocol()
753
        client_sock.sendall(rest_of_request_bytes)
754
        server._serve_one_request(server_protocol)
755
        server_sock.close()
756
        self.assertEqual(expected_response, client_sock.recv(50),
757
                         "Not a version 2 response to 'hello' request.")
758
        self.assertEqual('', client_sock.recv(1))
759
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
760
    def test_pipe_stream_incomplete_request(self):
761
        """The medium should still construct the right protocol version even if
762
        the initial read only reads part of the request.
763
764
        Specifically, it should correctly read the protocol version line even
765
        if the partial read doesn't end in a newline.  An older, naive
766
        implementation of _get_line in the server used to have a bug in that
767
        case.
768
        """
769
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
770
        rest_of_request_bytes = 'lo\n'
771
        expected_response = (
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
772
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
773
        # Make a pair of pipes, to and from the server
774
        to_server, to_server_w = os.pipe()
775
        from_server_r, from_server = os.pipe()
776
        to_server = os.fdopen(to_server, 'r', 0)
777
        to_server_w = os.fdopen(to_server_w, 'w', 0)
778
        from_server_r = os.fdopen(from_server_r, 'r', 0)
779
        from_server = os.fdopen(from_server, 'w', 0)
780
        server = medium.SmartServerPipeStreamMedium(
781
            to_server, from_server, None)
782
        # Like test_socket_stream_incomplete_request, write an incomplete
783
        # request (that does not end in '\n') and build a protocol from it.
784
        to_server_w.write(incomplete_request_bytes)
785
        server_protocol = server._build_protocol()
786
        # Send the rest of the request, and finish serving it.
787
        to_server_w.write(rest_of_request_bytes)
788
        server._serve_one_request(server_protocol)
789
        to_server_w.close()
790
        from_server.close()
791
        self.assertEqual(expected_response, from_server_r.read(),
792
                         "Not a version 2 response to 'hello' request.")
793
        self.assertEqual('', from_server_r.read(1))
794
        from_server_r.close()
795
        to_server.close()
796
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
797
    def test_pipe_like_stream_with_two_requests(self):
798
        # If two requests are read in one go, then two calls to
799
        # _serve_one_request should still process both of them as if they had
800
        # been received seperately.
801
        sample_request_bytes = 'command\n'
802
        to_server = StringIO(sample_request_bytes * 2)
803
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
804
        server = medium.SmartServerPipeStreamMedium(
805
            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.
806
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
807
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
808
        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.
809
        self.assertEqual('', from_server.getvalue())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
810
        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.
811
        # Make a new protocol, call _serve_one_request with it to collect the
812
        # second request.
813
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
814
        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.
815
        self.assertEqual('', from_server.getvalue())
816
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
817
        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.
818
        
819
    def test_socket_stream_with_two_requests(self):
820
        # If two requests are read in one go, then two calls to
821
        # _serve_one_request should still process both of them as if they had
822
        # been received seperately.
823
        sample_request_bytes = 'command\n'
824
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
825
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
826
            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.
827
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
828
        # Put two whole requests on the wire.
829
        client_sock.sendall(sample_request_bytes * 2)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
830
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
831
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
832
        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.
833
        # Make a new protocol, call _serve_one_request with it to collect the
834
        # second request.
835
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
836
        stream_still_open = server._serve_one_request(second_protocol)
837
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
838
        self.assertFalse(server.finished)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
839
        server_sock.close()
840
        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.
841
842
    def test_pipe_like_stream_error_handling(self):
843
        # Use plain python StringIO so we can monkey-patch the close method to
844
        # not discard the contents.
845
        from StringIO import StringIO
846
        to_server = StringIO('')
847
        from_server = StringIO()
848
        self.closed = False
849
        def close():
850
            self.closed = True
851
        from_server.close = close
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
852
        server = medium.SmartServerPipeStreamMedium(
853
            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.
854
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
855
        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.
856
        self.assertEqual('', from_server.getvalue())
857
        self.assertTrue(self.closed)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
858
        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.
859
        
860
    def test_socket_stream_error_handling(self):
861
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
862
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
863
            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.
864
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
865
        server._serve_one_request(fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
866
        # recv should not block, because the other end of the socket has been
867
        # closed.
868
        self.assertEqual('', client_sock.recv(1))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
869
        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.
870
        
871
    def test_pipe_like_stream_keyboard_interrupt_handling(self):
872
        to_server = StringIO('')
873
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
874
        server = medium.SmartServerPipeStreamMedium(
875
            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.
876
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
877
        self.assertRaises(
878
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
879
        self.assertEqual('', from_server.getvalue())
880
881
    def test_socket_stream_keyboard_interrupt_handling(self):
882
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
883
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
884
            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.
885
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
886
        self.assertRaises(
887
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
888
        server_sock.close()
889
        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.
890
891
    def build_protocol_pipe_like(self, bytes):
892
        to_server = StringIO(bytes)
893
        from_server = StringIO()
894
        server = medium.SmartServerPipeStreamMedium(
895
            to_server, from_server, None)
896
        return server._build_protocol()
897
898
    def build_protocol_socket(self, bytes):
899
        server_sock, client_sock = self.portable_socket_pair()
900
        server = medium.SmartServerSocketStreamMedium(
901
            server_sock, None)
902
        client_sock.sendall(bytes)
903
        client_sock.close()
904
        return server._build_protocol()
905
906
    def assertProtocolOne(self, server_protocol):
907
        # Use assertIs because assertIsInstance will wrongly pass
908
        # SmartServerRequestProtocolTwo (because it subclasses
909
        # SmartServerRequestProtocolOne).
910
        self.assertIs(
911
            type(server_protocol), protocol.SmartServerRequestProtocolOne)
912
913
    def assertProtocolTwo(self, server_protocol):
914
        self.assertIsInstance(
915
            server_protocol, protocol.SmartServerRequestProtocolTwo)
916
917
    def test_pipe_like_build_protocol_empty_bytes(self):
918
        # Any empty request (i.e. no bytes) is detected as protocol version one.
919
        server_protocol = self.build_protocol_pipe_like('')
920
        self.assertProtocolOne(server_protocol)
921
        
922
    def test_socket_like_build_protocol_empty_bytes(self):
923
        # Any empty request (i.e. no bytes) is detected as protocol version one.
924
        server_protocol = self.build_protocol_socket('')
925
        self.assertProtocolOne(server_protocol)
926
927
    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.
928
        # A request that doesn't start with "bzr request 2\n" is version one.
929
        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.
930
        self.assertProtocolOne(server_protocol)
931
932
    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.
933
        # A request that doesn't start with "bzr request 2\n" is version one.
934
        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.
935
        self.assertProtocolOne(server_protocol)
936
937
    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.
938
        # A request that starts with "bzr request 2\n" is version two.
939
        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.
940
        self.assertProtocolTwo(server_protocol)
941
942
    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.
943
        # A request that starts with "bzr request 2\n" is version two.
944
        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.
945
        self.assertProtocolTwo(server_protocol)
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
946
947
948
class TestGetProtocolFactoryForBytes(tests.TestCase):
949
    """_get_protocol_factory_for_bytes identifies the protocol factory a server
950
    should use to decode a given request.  Any bytes not part of the version
951
    marker string (and thus part of the actual request) are returned alongside
952
    the protocol factory.
953
    """
954
955
    def test_version_three(self):
956
        result = medium._get_protocol_factory_for_bytes(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
957
            'bzr message 3 (bzr 1.6)\nextra bytes')
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
958
        protocol_factory, remainder = result
959
        self.assertEqual(
960
            protocol.build_server_protocol_three, protocol_factory)
961
        self.assertEqual('extra bytes', remainder)
962
        
963
    def test_version_two(self):
964
        result = medium._get_protocol_factory_for_bytes(
965
            'bzr request 2\nextra bytes')
966
        protocol_factory, remainder = result
967
        self.assertEqual(
968
            protocol.SmartServerRequestProtocolTwo, protocol_factory)
969
        self.assertEqual('extra bytes', remainder)
970
        
971
    def test_version_one(self):
972
        """Version one requests have no version markers."""
973
        result = medium._get_protocol_factory_for_bytes('anything\n')
974
        protocol_factory, remainder = result
975
        self.assertEqual(
976
            protocol.SmartServerRequestProtocolOne, protocol_factory)
977
        self.assertEqual('anything\n', remainder)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
978
        
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
979
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
980
class TestSmartTCPServer(tests.TestCase):
981
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
982
    def test_get_error_unexpected(self):
983
        """Error reported by server with no specific representation"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
984
        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
985
        class FlakyTransport(object):
2376.3.3 by Robert Collins
Fix all smart_transport tests.
986
            base = 'a_url'
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
987
            def external_url(self):
988
                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.
989
            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
990
                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.
991
        smart_server = server.SmartTCPServer(backing_transport=FlakyTransport())
3245.4.28 by Andrew Bennetts
Remove another XXX, and include test ID in smart server thread names.
992
        smart_server.start_background_thread('-' + self.id())
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
993
        try:
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
994
            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
995
            try:
996
                transport.get('something')
997
            except errors.TransportError, e:
998
                self.assertContainsRe(str(e), 'some random exception')
999
            else:
1000
                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.
1001
            transport.disconnect()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1002
        finally:
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
1003
            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
1004
1005
1006
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1007
    """Tests for connection/end to end behaviour using the TCP server.
1008
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1009
    All of these tests are run with a server running on another thread serving
1010
    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`.
1011
1012
    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
1013
    """
1014
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1015
    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`.
1016
        """Setup the server.
1017
1018
        :param readonly: Create a readonly server.
1019
        """
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1020
        if not backing_transport:
1021
            self.backing_transport = memory.MemoryTransport()
1022
        else:
1023
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1024
        if readonly:
1025
            self.real_backing_transport = self.backing_transport
1026
            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.
1027
        self.server = server.SmartTCPServer(self.backing_transport)
3245.4.28 by Andrew Bennetts
Remove another XXX, and include test ID in smart server thread names.
1028
        self.server.start_background_thread('-' + self.id())
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1029
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1030
        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
1031
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1032
    def tearDownServer(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1033
        if getattr(self, 'transport', None):
1034
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1035
            del self.transport
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1036
        if getattr(self, 'server', None):
1037
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1038
            del self.server
1039
1040
1041
class TestServerSocketUsage(SmartTCPTests):
1042
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.
1043
    def test_server_setup_teardown(self):
1044
        """It should be safe to teardown the server with no requests."""
1045
        self.setUpServer()
1046
        server = self.server
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1047
        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.
1048
        self.tearDownServer()
1049
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1050
1051
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
1052
        """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
1053
        self.setUpServer()
2370.4.2 by Robert Collins
Review feedback.
1054
        server = self.server
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1055
        self.transport.has('.')
1056
        self.tearDownServer()
1057
        # if the listening socket has closed, we should get a BADFD error
1058
        # when connecting, rather than a hang.
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1059
        transport = remote.RemoteTCPTransport(server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1060
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1061
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1062
1063
class WritableEndToEndTests(SmartTCPTests):
1064
    """Client to server tests that require a writable transport."""
1065
1066
    def setUp(self):
1067
        super(WritableEndToEndTests, self).setUp()
1068
        self.setUpServer()
1069
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1070
    def test_start_tcp_server(self):
1071
        url = self.server.get_url()
1072
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
1073
1074
    def test_smart_transport_has(self):
1075
        """Checking for file existence over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1076
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1077
        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
1078
        self.assertTrue(self.transport.has("foo"))
1079
        self.assertFalse(self.transport.has("non-foo"))
1080
1081
    def test_smart_transport_get(self):
1082
        """Read back a file over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1083
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1084
        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
1085
        fp = self.transport.get("foo")
1086
        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`.
1087
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1088
    def test_get_error_enoent(self):
1089
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
1090
        # The path in a raised NoSuchFile exception should be the precise path
1091
        # asked for by the client. This gives meaningful and unsurprising errors
1092
        # for users.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1093
        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
1094
        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.
1095
            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
1096
        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.
1097
            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
1098
        else:
1099
            self.fail("get did not raise expected error")
1100
1101
    def test_simple_clone_conn(self):
1102
        """Test that cloning reuses the same connection."""
1103
        # we create a real connection not a loopback one, but it will use the
1104
        # 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__.
1105
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1106
        self.assertIs(self.transport.get_smart_medium(),
1107
                      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
1108
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)
1109
    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
1110
        self.assertEquals('/foo/bar',
1111
                          self.transport._remote_path('foo/bar'))
1112
1113
    def test_clone_changes_base(self):
1114
        """Cloning transport produces one with a new base location"""
1115
        conn2 = self.transport.clone('subdir')
1116
        self.assertEquals(self.transport.base + 'subdir/',
1117
                          conn2.base)
1118
1119
    def test_open_dir(self):
1120
        """Test changing directory"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1121
        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
1122
        transport = self.transport
1123
        self.backing_transport.mkdir('toffee')
1124
        self.backing_transport.mkdir('toffee/apple')
1125
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1126
        toffee_trans = transport.clone('toffee')
1127
        # Check that each transport has only the contents of its directory
1128
        # directly visible. If state was being held in the wrong object, it's
1129
        # conceivable that cloning a transport would alter the state of the
1130
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1131
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1132
        self.assertFalse(toffee_trans.has('toffee'))
1133
        self.assertFalse(transport.has('apple'))
1134
        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
1135
1136
    def test_open_bzrdir(self):
1137
        """Open an existing bzrdir over smart transport"""
1138
        transport = self.transport
1139
        t = self.backing_transport
1140
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
1141
        result_dir = bzrdir.BzrDir.open_containing_from_transport(transport)
1142
1143
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1144
class ReadOnlyEndToEndTests(SmartTCPTests):
1145
    """Tests from the client to the server using a readonly backing transport."""
1146
1147
    def test_mkdir_error_readonly(self):
1148
        """TransportNotPossible should be preserved from the backing transport."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1149
        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`.
1150
        self.setUpServer(readonly=True)
1151
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1152
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1153
1154
1155
class TestServerHooks(SmartTCPTests):
1156
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1157
    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
1158
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1159
        self.hook_calls.append((backing_urls, public_url))
1160
1161
    def test_server_started_hook_memory(self):
1162
        """The server_started hook fires when the server is started."""
1163
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1164
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1165
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1166
        self.setUpServer()
1167
        # at this point, the server will be starting a thread up.
1168
        # there is no indicator at the moment, so bodge it by doing a request.
1169
        self.transport.has('.')
1170
        # The default test server uses MemoryTransport and that has no external
1171
        # url:
1172
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1173
            self.hook_calls)
1174
1175
    def test_server_started_hook_file(self):
1176
        """The server_started hook fires when the server is started."""
1177
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1178
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1179
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1180
        self.setUpServer(backing_transport=get_transport("."))
1181
        # at this point, the server will be starting a thread up.
1182
        # there is no indicator at the moment, so bodge it by doing a request.
1183
        self.transport.has('.')
1184
        # The default test server uses MemoryTransport and that has no external
1185
        # url:
1186
        self.assertEqual([([
1187
            self.backing_transport.base, self.backing_transport.external_url()],
1188
             self.transport.base)],
1189
            self.hook_calls)
1190
1191
    def test_server_stopped_hook_simple_memory(self):
1192
        """The server_stopped hook fires when the server is stopped."""
1193
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1194
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1195
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1196
        self.setUpServer()
1197
        result = [([self.backing_transport.base], self.transport.base)]
1198
        # check the stopping message isn't emitted up front.
1199
        self.assertEqual([], self.hook_calls)
1200
        # nor after a single message
1201
        self.transport.has('.')
1202
        self.assertEqual([], self.hook_calls)
1203
        # clean up the server
1204
        self.tearDownServer()
1205
        # now it should have fired.
1206
        self.assertEqual(result, self.hook_calls)
1207
1208
    def test_server_stopped_hook_simple_file(self):
1209
        """The server_stopped hook fires when the server is stopped."""
1210
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1211
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1212
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1213
        self.setUpServer(backing_transport=get_transport("."))
1214
        result = [(
1215
            [self.backing_transport.base, self.backing_transport.external_url()]
1216
            , 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.
1217
        # check the stopping message isn't emitted up front.
1218
        self.assertEqual([], self.hook_calls)
1219
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1220
        self.transport.has('.')
1221
        self.assertEqual([], self.hook_calls)
1222
        # clean up the server
1223
        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.
1224
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1225
        self.assertEqual(result, self.hook_calls)
1226
1227
# TODO: test that when the server suffers an exception that it calls the
1228
# server-stopped hook.
1229
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1230
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1231
class SmartServerCommandTests(tests.TestCaseWithTransport):
1232
    """Tests that call directly into the command objects, bypassing the network
1233
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1234
1235
    Note: these tests are rudimentary versions of the command object tests in
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1236
    test_smart.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1237
    """
1238
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1239
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1240
        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)
1241
        response = cmd.execute()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1242
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1243
        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
1244
        
1245
    def test_get_bundle(self):
1246
        from bzrlib.bundle import serializer
1247
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1248
        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
1249
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1250
        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
1251
        
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1252
        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)
1253
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1254
        bundle = serializer.read_bundle(StringIO(response.body))
1255
        self.assertEqual((), response.args)
1256
1257
1258
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1259
    """Test that call directly into the handler logic, bypassing the network."""
1260
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1261
    def setUp(self):
1262
        super(SmartServerRequestHandlerTests, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
1263
        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)
1264
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1265
    def build_handler(self, transport):
1266
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1267
        return _mod_request.SmartServerRequestHandler(
1268
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1269
1270
    def test_construct_request_handler(self):
1271
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1272
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1273
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1274
        self.assertFalse(handler.finished_reading)
1275
1276
    def test_hello(self):
1277
        handler = self.build_handler(None)
1278
        handler.dispatch_command('hello', ())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1279
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1280
        self.assertEqual(None, handler.response.body)
1281
        
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)
1282
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1283
        # VFS handler classes will raise an error from "execute" if
1284
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1285
        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)
1286
        # set environment variable after construction to make sure it's
1287
        # examined.
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1288
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1289
        # 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)
1290
        # afterwards.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1291
        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)
1292
        self.assertRaises(errors.DisabledMethod, handler.execute)
1293
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1294
    def test_readonly_exception_becomes_transport_not_possible(self):
1295
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1296
        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`.
1297
        # send a mkdir for foo, with no explicit mode - should fail.
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1298
        handler.dispatch_command('mkdir', ('foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1299
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1300
        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`.
1301
        # XXX: TODO: test that other TransportNotPossible errors are
1302
        # presented as TransportNotPossible - not possible to do that
1303
        # until I figure out how to trigger that relatively cleanly via
1304
        # the api. RBC 20060918
1305
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1306
    def test_hello_has_finished_body_on_dispatch(self):
1307
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1308
        handler = self.build_handler(None)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1309
        handler.dispatch_command('hello', ())
1310
        self.assertTrue(handler.finished_reading)
1311
        self.assertNotEqual(None, handler.response)
1312
1313
    def test_put_bytes_non_atomic(self):
1314
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1315
        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
1316
        handler.dispatch_command('put_non_atomic', ('a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1317
        self.assertFalse(handler.finished_reading)
1318
        handler.accept_body('1234')
1319
        self.assertFalse(handler.finished_reading)
1320
        handler.accept_body('5678')
1321
        handler.end_of_body()
1322
        self.assertTrue(handler.finished_reading)
1323
        self.assertEqual(('ok', ), handler.response.args)
1324
        self.assertEqual(None, handler.response.body)
1325
        
1326
    def test_readv_accept_body(self):
1327
        """'readv' should set finished_reading after reading offsets."""
1328
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1329
        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
1330
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1331
        self.assertFalse(handler.finished_reading)
1332
        handler.accept_body('2,')
1333
        self.assertFalse(handler.finished_reading)
1334
        handler.accept_body('3')
1335
        handler.end_of_body()
1336
        self.assertTrue(handler.finished_reading)
1337
        self.assertEqual(('readv', ), handler.response.args)
1338
        # co - nte - nt of a-file is the file contents we are extracting from.
1339
        self.assertEqual('nte', handler.response.body)
1340
1341
    def test_readv_short_read_response_contents(self):
1342
        """'readv' when a short read occurs sets the response appropriately."""
1343
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1344
        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
1345
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1346
        # read beyond the end of the file.
1347
        handler.accept_body('100,1')
1348
        handler.end_of_body()
1349
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1350
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1351
            handler.response.args)
1352
        self.assertEqual(None, handler.response.body)
1353
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.
1354
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)
1355
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.
1356
1357
    def test_registration(self):
1358
        t = get_transport('bzr+ssh://example.com/path')
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1359
        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.
1360
        self.assertEqual('example.com', t._host)
1361
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1362
    def test_bzr_https(self):
1363
        # https://bugs.launchpad.net/bzr/+bug/128456
1364
        t = get_transport('bzr+https://example.com/path')
1365
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1366
        self.assertStartsWith(
1367
            t._http_transport.base,
1368
            'https://')
1369
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.
1370
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)
1371
class TestRemoteTransport(tests.TestCase):
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1372
        
1373
    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)
1374
        # We want to be able to pass a client as a parameter to RemoteTransport.
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1375
        input = StringIO('ok\n3\nbardone\n')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1376
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1377
        client_medium = medium.SmartSimplePipesClientMedium(
1378
            input, output, 'base')
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)
1379
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1380
            'bzr://localhost/', medium=client_medium)
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1381
        # Disable version detection.
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
1382
        client_medium._protocol_version = 1
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1383
1384
        # 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.
1385
        # method is called.  No data should have been sent, or read.
1386
        self.assertEqual(0, input.tell())
1387
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1388
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1389
        # Now call a method that should result in one request: as the
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1390
        # transport makes its own protocol instances, we check on the wire.
1391
        # XXX: TODO: give the transport a protocol factory, which can make
1392
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1393
        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.
1394
        # only the needed data should have been sent/received.
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1395
        self.assertEqual(13, input.tell())
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1396
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1397
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1398
    def test__translate_error_readonly(self):
1399
        """Sending a ReadOnlyError to _translate_error raises TransportNotPossible."""
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1400
        client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
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)
1401
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1402
            'bzr://localhost/', medium=client_medium)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1403
        self.assertRaises(errors.TransportNotPossible,
1404
            transport._translate_error, ("ReadOnlyError", ))
1405
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1406
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1407
class TestSmartProtocol(tests.TestCase):
1408
    """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.
1409
1410
    Each test case gets a smart_server and smart_client created during setUp().
1411
1412
    It is planned that the client can be called with self.call_client() giving
1413
    it an expected server response, which will be fed into it when it tries to
1414
    read. Likewise, self.call_server will call a servers method with a canned
1415
    serialised client request. Output done by the client or server for these
1416
    calls will be captured to self.to_server and self.to_client. Each element
1417
    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.
1418
1419
    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.
1420
    """
1421
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1422
    request_encoder = None
1423
    response_decoder = None
1424
    server_protocol_class = None
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1425
    client_protocol_class = None
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1426
1427
    def make_client_protocol_and_output(self, input_bytes=None):
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
1428
        """
1429
        :returns: a Request
1430
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1431
        # This is very similar to
1432
        # bzrlib.smart.client._SmartClient._build_client_protocol
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1433
        # XXX: make this use _SmartClient!
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1434
        if input_bytes is None:
1435
            input = StringIO()
1436
        else:
1437
            input = StringIO(input_bytes)
1438
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1439
        client_medium = medium.SmartSimplePipesClientMedium(
1440
            input, output, 'base')
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1441
        request = client_medium.get_request()
1442
        if self.client_protocol_class is not None:
1443
            client_protocol = self.client_protocol_class(request)
1444
            return client_protocol, client_protocol, output
1445
        else:
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
1446
            self.assertNotEqual(None, self.request_encoder)
1447
            self.assertNotEqual(None, self.response_decoder)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1448
            requester = self.request_encoder(request)
1449
            response_handler = message.ConventionalResponseHandler()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1450
            response_protocol = self.response_decoder(
1451
                response_handler, expect_version_marker=True)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
1452
            response_handler.setProtoAndMediumRequest(
1453
                response_protocol, request)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1454
            return requester, response_handler, output
1455
1456
    def make_client_protocol(self, input_bytes=None):
1457
        result = self.make_client_protocol_and_output(input_bytes=input_bytes)
1458
        requester, response_handler, output = result
1459
        return requester, response_handler
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.
1460
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1461
    def make_server_protocol(self):
1462
        out_stream = StringIO()
3245.4.34 by Andrew Bennetts
Remove another insignificant change vs. bzr.dev.
1463
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1464
        return smart_protocol, out_stream
1465
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
    def setUp(self):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1467
        super(TestSmartProtocol, self).setUp()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1468
        self.response_marker = getattr(
1469
            self.client_protocol_class, 'response_marker', None)
1470
        self.request_marker = getattr(
1471
            self.client_protocol_class, 'request_marker', None)
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.
1472
1473
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1474
        requester):
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.
1475
        """Check that smart (de)serialises offsets as expected.
1476
        
1477
        We check both serialisation and deserialisation at the same time
1478
        to ensure that the round tripping cannot skew: both directions should
1479
        be as expected.
1480
        
1481
        :param expected_offsets: a readv offset list.
1482
        :param expected_seralised: an expected serial form of the offsets.
1483
        """
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.
1484
        # XXX: '_deserialise_offsets' should be a method of the
1485
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1486
        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.
1487
        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.
1488
        self.assertEqual(expected_offsets, offsets)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1489
        serialised = requester._serialise_offsets(offsets)
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.
1490
        self.assertEqual(expected_serialised, serialised)
1491
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1492
    def build_protocol_waiting_for_body(self):
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1493
        smart_protocol, out_stream = self.make_server_protocol()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1494
        smart_protocol._has_dispatched = True
3245.1.14 by Andrew Bennetts
Merge from bzr.dev
1495
        smart_protocol.request = _mod_request.SmartServerRequestHandler(
1496
            None, _mod_request.request_handlers, '/')
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1497
        class FakeCommand(object):
1498
            def do_body(cmd, body_bytes):
1499
                self.end_received = True
1500
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1501
                return _mod_request.SuccessfulSmartServerResponse(('ok', ))
2018.5.12 by Andrew Bennetts
Rename SmartServerRequestHandler's command attribute to _command; it's private.
1502
        smart_protocol.request._command = FakeCommand()
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1503
        # Call accept_bytes to make sure that internal state like _body_decoder
1504
        # is initialised.  This test should probably be given a clearer
1505
        # interface to work with that will not cause this inconsistency.
1506
        #   -- 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
1507
        smart_protocol.accept_bytes('')
1508
        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.
1509
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1510
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
1511
            input_tuples):
1512
        """Assert that each input_tuple serialises as expected_bytes, and the
1513
        bytes deserialise as expected_tuple.
1514
        """
1515
        # check the encoding of the server for all input_tuples matches
1516
        # expected bytes
1517
        for input_tuple in input_tuples:
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1518
            server_protocol, server_output = self.make_server_protocol()
2432.4.4 by Robert Collins
Merge hpss-protocol2.
1519
            server_protocol._send_response(
1520
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1521
            self.assertEqual(expected_bytes, server_output.getvalue())
1522
        # check the decoding of the client smart_protocol from expected_bytes:
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1523
        requester, response_handler = self.make_client_protocol(expected_bytes)
1524
        requester.call('foo')
1525
        self.assertEqual(expected_tuple, response_handler.read_response_tuple())
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1526
1527
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.
1528
class CommonSmartProtocolTestMixin(object):
1529
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1530
    def test_connection_closed_reporting(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1531
        requester, response_handler = self.make_client_protocol()
1532
        requester.call('hello')
3245.1.10 by Andrew Bennetts
Remove trailing whitespace.
1533
        ex = self.assertRaises(errors.ConnectionReset,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1534
            response_handler.read_response_tuple)
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1535
        self.assertEqual("Connection closed: "
1536
            "please check connectivity and permissions "
1537
            "(and try -Dhpss if further diagnosis is required)", str(ex))
1538
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1539
    def test_server_offset_serialisation(self):
1540
        """The Smart protocol serialises offsets as a comma and \n string.
1541
1542
        We check a number of boundary cases are as expected: empty, one offset,
1543
        one with the order of reads not increasing (an out of order read), and
1544
        one that should coalesce.
1545
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1546
        requester, response_handler = self.make_client_protocol()
1547
        self.assertOffsetSerialisation([], '', requester)
1548
        self.assertOffsetSerialisation([(1,2)], '1,2', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1549
        self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5',
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1550
            requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1551
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1552
            '1,2\n3,4\n100,200', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1553
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.
1554
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1555
class TestVersionOneFeaturesInProtocolOne(
1556
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1557
    """Tests for version one smart protocol features as implemeted by version
1558
    one."""
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1559
1560
    client_protocol_class = protocol.SmartClientRequestProtocolOne
1561
    server_protocol_class = protocol.SmartServerRequestProtocolOne
1562
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1563
    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
1564
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1565
        self.assertEqual('', smart_protocol.unused_data)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1566
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1567
        self.assertFalse(smart_protocol._has_dispatched)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1568
        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.
1569
1570
    def test_construct_version_one_client_protocol(self):
1571
        # we can construct a client protocol from a client medium request
1572
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1573
        client_medium = medium.SmartSimplePipesClientMedium(
1574
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1575
        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
1576
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1577
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1578
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1579
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1580
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1581
            None, out_stream.write)
1582
        smart_protocol.accept_bytes('abc')
1583
        self.assertEqual('abc', smart_protocol.in_buffer)
1584
        smart_protocol.accept_bytes('\n')
1585
        self.assertEqual(
1586
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
1587
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1588
        self.assertTrue(smart_protocol._has_dispatched)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1589
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
1590
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1591
    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.
1592
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1593
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1594
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1595
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1596
        protocol.accept_bytes('defgd')
1597
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1598
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1599
        self.assertTrue(self.end_received)
1600
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1601
    def test_accept_request_and_body_all_at_once(self):
2402.1.2 by Andrew Bennetts
Deal with review comments.
1602
        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.
1603
        mem_transport = memory.MemoryTransport()
1604
        mem_transport.put_bytes('foo', 'abcdefghij')
1605
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1606
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
1607
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1608
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1609
        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.
1610
        self.assertEqual('readv\n3\ndefdone\n', out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1611
        self.assertEqual('', smart_protocol.unused_data)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1612
        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.
1613
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1614
    def test_accept_excess_bytes_are_preserved(self):
1615
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1616
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1617
            None, out_stream.write)
1618
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1619
        self.assertEqual("ok\x012\n", out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1620
        self.assertEqual("hello\n", smart_protocol.unused_data)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1621
        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.
1622
1623
    def test_accept_excess_bytes_after_body(self):
1624
        protocol = self.build_protocol_waiting_for_body()
1625
        protocol.accept_bytes('7\nabcdefgdone\nX')
1626
        self.assertTrue(self.end_received)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1627
        self.assertEqual("X", protocol.unused_data)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1628
        self.assertEqual("", protocol.in_buffer)
1629
        protocol.accept_bytes('Y')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1630
        self.assertEqual("XY", protocol.unused_data)
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1631
        self.assertEqual("", protocol.in_buffer)
1632
1633
    def test_accept_excess_bytes_after_dispatch(self):
1634
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1635
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1636
            None, out_stream.write)
1637
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1638
        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
1639
        smart_protocol.accept_bytes('hel')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1640
        self.assertEqual("hel", smart_protocol.unused_data)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1641
        smart_protocol.accept_bytes('lo\n')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1642
        self.assertEqual("hello\n", smart_protocol.unused_data)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1643
        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.
1644
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1645
    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
1646
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1647
            None, lambda x: None)
1648
        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.
1649
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1650
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1651
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1652
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1653
    def test__send_response_errors_with_base_response(self):
1654
        """Ensure that only the Successful/Failed subclasses are used."""
1655
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1656
            None, lambda x: None)
1657
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1658
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1659
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1660
    def test_query_version(self):
1661
        """query_version on a SmartClientProtocolOne should return a number.
1662
        
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1663
        The protocol provides the query_version because the domain level clients
1664
        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.
1665
        """
1666
        # What we really want to test here is that SmartClientProtocolOne calls
1667
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1668
        # 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.
1669
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1670
        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.
1671
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1672
        client_medium = medium.SmartSimplePipesClientMedium(
1673
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1674
        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
1675
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1676
        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.
1677
1678
    def test_client_call_empty_response(self):
1679
        # protocol.call() can get back an empty tuple as a response. This occurs
1680
        # when the parsed line is an empty line, and results in a tuple with
1681
        # one element - an empty string.
1682
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
1683
1684
    def test_client_call_three_element_response(self):
1685
        # protocol.call() can get back tuples of other lengths. A three element
1686
        # tuple should be unpacked as three strings.
1687
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
1688
            [('a', 'b', '34')])
1689
1690
    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.
1691
        # 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.
1692
        # wire.
1693
        expected_bytes = "foo\n7\nabcdefgdone\n"
1694
        input = StringIO("\n")
1695
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1696
        client_medium = medium.SmartSimplePipesClientMedium(
1697
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1698
        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
1699
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1700
        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.
1701
        self.assertEqual(expected_bytes, output.getvalue())
1702
1703
    def test_client_call_with_body_readv_array(self):
1704
        # protocol.call_with_upload should encode the readv array and then
1705
        # length-prefix the bytes onto the wire.
1706
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
1707
        input = StringIO("\n")
1708
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1709
        client_medium = medium.SmartSimplePipesClientMedium(
1710
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1711
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1712
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1713
        smart_protocol.call_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.
1714
        self.assertEqual(expected_bytes, output.getvalue())
1715
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
1716
    def _test_client_read_response_tuple_raises_UnknownSmartMethod(self,
1717
            server_bytes):
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1718
        input = StringIO(server_bytes)
1719
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1720
        client_medium = medium.SmartSimplePipesClientMedium(
1721
            input, output, 'base')
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1722
        request = client_medium.get_request()
1723
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1724
        smart_protocol.call('foo')
1725
        self.assertRaises(
1726
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
1727
        # The request has been finished.  There is no body to read, and
1728
        # attempts to read one will fail.
1729
        self.assertRaises(
1730
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1731
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
1732
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
1733
        """read_response_tuple raises UnknownSmartMethod if the response says
1734
        the server did not recognise the request.
1735
        """
1736
        server_bytes = (
1737
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
1738
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1739
            server_bytes)
1740
1741
    def test_client_read_response_tuple_raises_UnknownSmartMethod_0_11(self):
1742
        """read_response_tuple also raises UnknownSmartMethod if the response
1743
        from a bzr 0.11 says the server did not recognise the request.
1744
1745
        (bzr 0.11 sends a slightly different error message to later versions.)
1746
        """
1747
        server_bytes = (
1748
            "error\x01Generic bzr smart protocol error: bad request u'foo'\n")
1749
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1750
            server_bytes)
1751
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1752
    def test_client_read_body_bytes_all(self):
1753
        # read_body_bytes should decode the body bytes from the wire into
1754
        # a response.
1755
        expected_bytes = "1234567"
1756
        server_bytes = "ok\n7\n1234567done\n"
1757
        input = StringIO(server_bytes)
1758
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1759
        client_medium = medium.SmartSimplePipesClientMedium(
1760
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1761
        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
1762
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1763
        smart_protocol.call('foo')
1764
        smart_protocol.read_response_tuple(True)
1765
        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.
1766
1767
    def test_client_read_body_bytes_incremental(self):
1768
        # test reading a few bytes at a time from the body
1769
        # 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.
1770
        # 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.
1771
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1772
        # that.
1773
        expected_bytes = "1234567"
1774
        server_bytes = "ok\n7\n1234567done\n"
1775
        input = StringIO(server_bytes)
1776
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1777
        client_medium = medium.SmartSimplePipesClientMedium(
1778
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1779
        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
1780
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1781
        smart_protocol.call('foo')
1782
        smart_protocol.read_response_tuple(True)
1783
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1784
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1785
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1786
        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.
1787
1788
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1789
        # cancelling the expected body needs to finish the request, but not
1790
        # read any more bytes.
1791
        expected_bytes = "1234567"
1792
        server_bytes = "ok\n7\n1234567done\n"
1793
        input = StringIO(server_bytes)
1794
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1795
        client_medium = medium.SmartSimplePipesClientMedium(
1796
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1797
        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
1798
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1799
        smart_protocol.call('foo')
1800
        smart_protocol.read_response_tuple(True)
1801
        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.
1802
        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
1803
        self.assertRaises(
1804
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1805
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1806
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1807
class TestVersionOneFeaturesInProtocolTwo(
1808
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1809
    """Tests for version one smart protocol features as implemeted by version
1810
    two.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1811
    """
1812
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1813
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
1814
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1815
1816
    def test_construct_version_two_server_protocol(self):
1817
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1818
        self.assertEqual('', smart_protocol.unused_data)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1819
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1820
        self.assertFalse(smart_protocol._has_dispatched)
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1821
        self.assertEqual(1, smart_protocol.next_read_size())
1822
1823
    def test_construct_version_two_client_protocol(self):
1824
        # we can construct a client protocol from a client medium request
1825
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1826
        client_medium = medium.SmartSimplePipesClientMedium(
1827
            None, output, 'base')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1828
        request = client_medium.get_request()
1829
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1830
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1831
    def test_accept_bytes_of_bad_request_to_protocol(self):
1832
        out_stream = StringIO()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1833
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1834
        smart_protocol.accept_bytes('abc')
1835
        self.assertEqual('abc', smart_protocol.in_buffer)
1836
        smart_protocol.accept_bytes('\n')
1837
        self.assertEqual(
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1838
            self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1839
            "failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
1840
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1841
        self.assertTrue(smart_protocol._has_dispatched)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1842
        self.assertEqual(0, smart_protocol.next_read_size())
1843
1844
    def test_accept_body_bytes_to_protocol(self):
1845
        protocol = self.build_protocol_waiting_for_body()
1846
        self.assertEqual(6, protocol.next_read_size())
1847
        protocol.accept_bytes('7\nabc')
1848
        self.assertEqual(9, protocol.next_read_size())
1849
        protocol.accept_bytes('defgd')
1850
        protocol.accept_bytes('one\n')
1851
        self.assertEqual(0, protocol.next_read_size())
1852
        self.assertTrue(self.end_received)
1853
1854
    def test_accept_request_and_body_all_at_once(self):
1855
        self._captureVar('BZR_NO_SMART_VFS', None)
1856
        mem_transport = memory.MemoryTransport()
1857
        mem_transport.put_bytes('foo', 'abcdefghij')
1858
        out_stream = StringIO()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1859
        smart_protocol = self.server_protocol_class(
1860
            mem_transport, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1861
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1862
        self.assertEqual(0, smart_protocol.next_read_size())
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1863
        self.assertEqual(self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1864
                         'success\nreadv\n3\ndefdone\n',
1865
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1866
        self.assertEqual('', smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1867
        self.assertEqual('', smart_protocol.in_buffer)
1868
1869
    def test_accept_excess_bytes_are_preserved(self):
1870
        out_stream = StringIO()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1871
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1872
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1873
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1874
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1875
        self.assertEqual("hello\n", smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1876
        self.assertEqual("", smart_protocol.in_buffer)
1877
1878
    def test_accept_excess_bytes_after_body(self):
1879
        # The excess bytes look like the start of another request.
1880
        server_protocol = self.build_protocol_waiting_for_body()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1881
        server_protocol.accept_bytes('7\nabcdefgdone\n' + self.response_marker)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1882
        self.assertTrue(self.end_received)
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1883
        self.assertEqual(self.response_marker,
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1884
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1885
        self.assertEqual("", server_protocol.in_buffer)
1886
        server_protocol.accept_bytes('Y')
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1887
        self.assertEqual(self.response_marker + "Y",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1888
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1889
        self.assertEqual("", server_protocol.in_buffer)
1890
1891
    def test_accept_excess_bytes_after_dispatch(self):
1892
        out_stream = StringIO()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1893
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1894
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1895
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1896
                         out_stream.getvalue())
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1897
        smart_protocol.accept_bytes(self.request_marker + 'hel')
1898
        self.assertEqual(self.request_marker + "hel",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1899
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1900
        smart_protocol.accept_bytes('lo\n')
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1901
        self.assertEqual(self.request_marker + "hello\n",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1902
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1903
        self.assertEqual("", smart_protocol.in_buffer)
1904
1905
    def test__send_response_sets_finished_reading(self):
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1906
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1907
        self.assertEqual(1, smart_protocol.next_read_size())
1908
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1909
            _mod_request.SuccessfulSmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1910
        self.assertEqual(0, smart_protocol.next_read_size())
1911
1912
    def test__send_response_errors_with_base_response(self):
1913
        """Ensure that only the Successful/Failed subclasses are used."""
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1914
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1915
        self.assertRaises(AttributeError, smart_protocol._send_response,
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1916
            _mod_request.SmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1917
1918
    def test_query_version(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
1919
        """query_version on a SmartClientProtocolTwo should return a number.
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1920
        
1921
        The protocol provides the query_version because the domain level clients
1922
        may all need to be able to probe for capabilities.
1923
        """
1924
        # What we really want to test here is that SmartClientProtocolTwo calls
1925
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1926
        # response of tuple-encoded (ok, 1).  Also, seperately we should test
1927
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1928
        input = StringIO(self.response_marker + 'success\nok\x012\n')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1929
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1930
        client_medium = medium.SmartSimplePipesClientMedium(
1931
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1932
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1933
        smart_protocol = self.client_protocol_class(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1934
        self.assertEqual(2, smart_protocol.query_version())
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1935
1936
    def test_client_call_empty_response(self):
1937
        # protocol.call() can get back an empty tuple as a response. This occurs
1938
        # when the parsed line is an empty line, and results in a tuple with
1939
        # one element - an empty string.
1940
        self.assertServerToClientEncoding(
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1941
            self.response_marker + 'success\n\n', ('', ), [(), ('', )])
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1942
1943
    def test_client_call_three_element_response(self):
1944
        # protocol.call() can get back tuples of other lengths. A three element
1945
        # tuple should be unpacked as three strings.
1946
        self.assertServerToClientEncoding(
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1947
            self.response_marker + 'success\na\x01b\x0134\n',
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1948
            ('a', 'b', '34'),
1949
            [('a', 'b', '34')])
1950
1951
    def test_client_call_with_body_bytes_uploads(self):
1952
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
1953
        # wire.
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1954
        expected_bytes = self.request_marker + "foo\n7\nabcdefgdone\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1955
        input = StringIO("\n")
1956
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1957
        client_medium = medium.SmartSimplePipesClientMedium(
1958
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1959
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1960
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1961
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1962
        self.assertEqual(expected_bytes, output.getvalue())
1963
1964
    def test_client_call_with_body_readv_array(self):
1965
        # protocol.call_with_upload should encode the readv array and then
1966
        # length-prefix the bytes onto the wire.
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1967
        expected_bytes = self.request_marker + "foo\n7\n1,2\n5,6done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1968
        input = StringIO("\n")
1969
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1970
        client_medium = medium.SmartSimplePipesClientMedium(
1971
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1972
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1973
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1974
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1975
        self.assertEqual(expected_bytes, output.getvalue())
1976
1977
    def test_client_read_body_bytes_all(self):
1978
        # read_body_bytes should decode the body bytes from the wire into
1979
        # a response.
1980
        expected_bytes = "1234567"
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1981
        server_bytes = (self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1982
                        "success\nok\n7\n1234567done\n")
1983
        input = StringIO(server_bytes)
1984
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
1985
        client_medium = medium.SmartSimplePipesClientMedium(
1986
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1987
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
1988
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1989
        smart_protocol.call('foo')
1990
        smart_protocol.read_response_tuple(True)
1991
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
1992
1993
    def test_client_read_body_bytes_incremental(self):
1994
        # test reading a few bytes at a time from the body
1995
        # XXX: possibly we should test dribbling the bytes into the stringio
1996
        # to make the state machine work harder: however, as we use the
1997
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1998
        # that.
1999
        expected_bytes = "1234567"
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2000
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2001
        input = StringIO(server_bytes)
2002
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2003
        client_medium = medium.SmartSimplePipesClientMedium(
2004
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2005
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2006
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2007
        smart_protocol.call('foo')
2008
        smart_protocol.read_response_tuple(True)
2009
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2010
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2011
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2012
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2013
2014
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2015
        # cancelling the expected body needs to finish the request, but not
2016
        # read any more bytes.
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2017
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2018
        input = StringIO(server_bytes)
2019
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2020
        client_medium = medium.SmartSimplePipesClientMedium(
2021
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2022
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2023
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2024
        smart_protocol.call('foo')
2025
        smart_protocol.read_response_tuple(True)
2026
        smart_protocol.cancel_read_body()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2027
        self.assertEqual(len(self.response_marker + 'success\nok\n'),
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2028
                         input.tell())
2029
        self.assertRaises(
2030
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2031
2032
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2033
class TestSmartProtocolTwoSpecificsMixin(object):
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2034
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2035
    def assertBodyStreamSerialisation(self, expected_serialisation,
2036
                                      body_stream):
2037
        """Assert that body_stream is serialised as expected_serialisation."""
2038
        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.
2039
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
2040
        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.
2041
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.
2042
    def assertBodyStreamRoundTrips(self, body_stream):
2043
        """Assert that body_stream is the same after being serialised and
2044
        deserialised.
2045
        """
2046
        out_stream = StringIO()
2047
        protocol._send_stream(body_stream, out_stream.write)
2048
        decoder = protocol.ChunkedBodyDecoder()
2049
        decoder.accept_bytes(out_stream.getvalue())
2050
        decoded_stream = list(iter(decoder.read_next_chunk, None))
2051
        self.assertEqual(body_stream, decoded_stream)
2052
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2053
    def test_body_stream_serialisation_empty(self):
2054
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2055
        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.
2056
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2057
2058
    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.
2059
        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.
2060
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2061
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
2062
            '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.
2063
            stream)
2064
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2065
2066
    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.
2067
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2068
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2069
        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.
2070
        """
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.
2071
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2072
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2073
            '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.
2074
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2075
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2076
    def test_body_stream_error_serialistion(self):
2077
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2078
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2079
                      ('FailureName', 'failure arg'))]
2080
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2081
            '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.
2082
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
2083
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2084
        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.
2085
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2086
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2087
    def test__send_response_includes_failure_marker(self):
2088
        """FailedSmartServerResponse have 'failed\n' after the version."""
2089
        out_stream = StringIO()
2090
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2091
            None, out_stream.write)
2092
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2093
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2094
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
2095
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2096
2097
    def test__send_response_includes_success_marker(self):
2098
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
2099
        out_stream = StringIO()
2100
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2101
            None, out_stream.write)
2102
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2103
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2104
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
2105
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2106
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2107
    def test__send_response_with_body_stream_sets_finished_reading(self):
2108
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2109
            None, lambda x: None)
2110
        self.assertEqual(1, smart_protocol.next_read_size())
2111
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2112
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2113
        self.assertEqual(0, smart_protocol.next_read_size())
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2114
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2115
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2116
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2117
        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.
2118
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2119
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2120
                        "success\nok\n" + body_header + two_body_chunks +
2121
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2122
        input = StringIO(server_bytes)
2123
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2124
        client_medium = medium.SmartSimplePipesClientMedium(
2125
            input, output, 'base')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2126
        request = client_medium.get_request()
2127
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2128
        smart_protocol.call('foo')
2129
        smart_protocol.read_response_tuple(True)
2130
        stream = smart_protocol.read_streamed_body()
2131
        self.assertEqual(['1234', '567'], list(stream))
2132
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2133
    def test_read_streamed_body_error(self):
2134
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2135
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2136
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2137
        err_signal = 'ERR\n'
2138
        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.
2139
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2140
        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.
2141
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2142
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2143
        input = StringIO(server_bytes)
2144
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2145
        client_medium = medium.SmartSimplePipesClientMedium(
2146
            input, output, 'base')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2147
        smart_request = client_medium.get_request()
2148
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2149
        smart_protocol.call('foo')
2150
        smart_protocol.read_response_tuple(True)
2151
        expected_chunks = [
2152
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2153
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2154
        stream = smart_protocol.read_streamed_body()
2155
        self.assertEqual(expected_chunks, list(stream))
2156
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2157
    def test_client_read_response_tuple_sets_response_status(self):
2158
        server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
2159
        input = StringIO(server_bytes)
2160
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2161
        client_medium = medium.SmartSimplePipesClientMedium(
2162
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2163
        request = client_medium.get_request()
2164
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2165
        smart_protocol.call('foo')
2166
        smart_protocol.read_response_tuple(False)
2167
        self.assertEqual(True, smart_protocol.response_status)
2168
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2169
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2170
        """read_response_tuple raises UnknownSmartMethod if the response says
2171
        the server did not recognise the request.
2172
        """
2173
        server_bytes = (
2174
            protocol.RESPONSE_VERSION_TWO +
2175
            "failed\n" +
2176
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2177
        input = StringIO(server_bytes)
2178
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2179
        client_medium = medium.SmartSimplePipesClientMedium(
2180
            input, output, 'base')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2181
        request = client_medium.get_request()
2182
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2183
        smart_protocol.call('foo')
2184
        self.assertRaises(
2185
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2186
        # The request has been finished.  There is no body to read, and
2187
        # attempts to read one will fail.
2188
        self.assertRaises(
2189
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2190
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2191
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2192
class TestSmartProtocolTwoSpecifics(
2193
        TestSmartProtocol, TestSmartProtocolTwoSpecificsMixin):
2194
    """Tests for aspects of smart protocol version two that are unique to
2195
    version two.
2196
2197
    Thus tests involving body streams and success/failure markers belong here.
2198
    """
2199
2200
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
2201
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2202
2203
2204
class TestVersionOneFeaturesInProtocolThree(
2205
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2206
    """Tests for version one smart protocol features as implemented by version
2207
    three.
2208
    """
2209
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2210
    request_encoder = protocol.ProtocolThreeRequester
2211
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2212
    # build_server_protocol_three is a function, so we can't set it as a class
2213
    # attribute directly, because then Python will assume it is actually a
3245.4.10 by Andrew Bennetts
Use a less ugly hack for TestVersionOneFeaturesInProtocolThree.server_protocol_class.
2214
    # method.  So we make server_protocol_class be a static method, rather than
2215
    # simply doing:
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2216
    # "server_protocol_class = protocol.build_server_protocol_three".
3245.4.10 by Andrew Bennetts
Use a less ugly hack for TestVersionOneFeaturesInProtocolThree.server_protocol_class.
2217
    server_protocol_class = staticmethod(protocol.build_server_protocol_three)
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2218
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2219
    def setUp(self):
2220
        super(TestVersionOneFeaturesInProtocolThree, self).setUp()
2221
        self.response_marker = protocol.MESSAGE_VERSION_THREE
2222
        self.request_marker = protocol.MESSAGE_VERSION_THREE
2223
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2224
    def test_construct_version_three_server_protocol(self):
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2225
        smart_protocol = protocol.ProtocolThreeDecoder(None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2226
        self.assertEqual('', smart_protocol.unused_data)
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2227
        self.assertEqual('', smart_protocol._in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2228
        self.assertFalse(smart_protocol._has_dispatched)
3195.3.19 by Andrew Bennetts
Remove a stray pdb, fix a test.
2229
        # The protocol starts by expecting four bytes, a length prefix for the
2230
        # headers.
2231
        self.assertEqual(4, smart_protocol.next_read_size())
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2232
2233
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2234
class NoOpRequest(_mod_request.SmartServerRequest):
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
2235
2236
    def do(self):
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2237
        return _mod_request.SuccessfulSmartServerResponse(())
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
2238
2239
dummy_registry = {'ARG': NoOpRequest}
2240
2241
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2242
class LoggingMessageHandler(object):
2243
2244
    def __init__(self):
2245
        self.event_log = []
2246
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2247
    def _log(self, *args):
2248
        self.event_log.append(args)
2249
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2250
    def headers_received(self, headers):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2251
        self._log('headers', headers)
2252
2253
    def protocol_error(self, exception):
2254
        self._log('protocol_error', exception)
2255
2256
    def byte_part_received(self, byte):
2257
        self._log('byte', byte)
2258
2259
    def bytes_part_received(self, bytes):
2260
        self._log('bytes', bytes)
2261
2262
    def structure_part_received(self, structure):
2263
        self._log('structure', structure)
2264
2265
    def end_received(self):
2266
        self._log('end')
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2267
2268
2269
class TestProtocolThree(TestSmartProtocol):
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2270
    """Tests for v3 of the server-side protocol."""
2271
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2272
    request_encoder = protocol.ProtocolThreeRequester
2273
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2274
    server_protocol_class = protocol.ProtocolThreeDecoder
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2275
2276
    def test_trivial_request(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2277
        """Smoke test for the simplest possible v3 request: empty headers, no
2278
        message parts.
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2279
        """
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2280
        output = StringIO()
2281
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2282
        end = 'e'
2283
        request_bytes = headers + end
2284
        smart_protocol = self.server_protocol_class(LoggingMessageHandler())
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2285
        smart_protocol.accept_bytes(request_bytes)
2286
        self.assertEqual(0, smart_protocol.next_read_size())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2287
        self.assertEqual('', smart_protocol.unused_data)
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2288
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2289
    def make_protocol_expecting_message_part(self):
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2290
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2291
        message_handler = LoggingMessageHandler()
2292
        smart_protocol = self.server_protocol_class(message_handler)
2293
        smart_protocol.accept_bytes(headers)
2294
        # Clear the event log
2295
        del message_handler.event_log[:]
2296
        return smart_protocol, message_handler.event_log
2297
2298
    def test_decode_one_byte(self):
2299
        """The protocol can decode a 'one byte' message part."""
2300
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2301
        smart_protocol.accept_bytes('ox')
2302
        self.assertEqual([('byte', 'x')], event_log)
2303
2304
    def test_decode_bytes(self):
2305
        """The protocol can decode a 'bytes' message part."""
2306
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2307
        smart_protocol.accept_bytes(
2308
            'b' # message part kind
2309
            '\0\0\0\x07' # length prefix
2310
            'payload' # payload
2311
            )
2312
        self.assertEqual([('bytes', 'payload')], event_log)
2313
2314
    def test_decode_structure(self):
2315
        """The protocol can decode a 'structure' message part."""
2316
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2317
        smart_protocol.accept_bytes(
2318
            's' # message part kind
2319
            '\0\0\0\x07' # length prefix
2320
            'l3:ARGe' # ['ARG']
2321
            )
2322
        self.assertEqual([('structure', ['ARG'])], event_log)
2323
2324
    def test_decode_multiple_bytes(self):
2325
        """The protocol can decode a multiple 'bytes' message parts."""
2326
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2327
        smart_protocol.accept_bytes(
2328
            'b' # message part kind
2329
            '\0\0\0\x05' # length prefix
2330
            'first' # payload
2331
            'b' # message part kind
2332
            '\0\0\0\x06'
2333
            'second'
2334
            )
2335
        self.assertEqual(
2336
            [('bytes', 'first'), ('bytes', 'second')], event_log)
2337
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2338
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2339
class TestConventionalResponseHandler(tests.TestCase):
2340
2341
    def test_interrupted_body_stream(self):
2342
        interrupted_body_stream = (
2343
            'oS' # successful response
2344
            's\0\0\0\x02le' # empty args
2345
            'b\0\0\0\x09chunk one' # first chunk
2346
            'b\0\0\0\x09chunk two' # second chunk
2347
            'oE' # error flag
2348
            's\0\0\0\x0el5:error3:abce' # bencoded error
2349
            'e' # message end
2350
            )
2351
        from bzrlib.smart.message import ConventionalResponseHandler
2352
        response_handler = ConventionalResponseHandler()
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2353
        protocol_decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2354
        # put decoder in desired state (waiting for message parts)
2355
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2356
        output = StringIO()
2357
        client_medium = medium.SmartSimplePipesClientMedium(
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2358
            StringIO(interrupted_body_stream), output, 'base')
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2359
        medium_request = client_medium.get_request()
2360
        medium_request.finished_writing()
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2361
        response_handler.setProtoAndMediumRequest(
2362
            protocol_decoder, medium_request)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2363
        stream = response_handler.read_streamed_body()
2364
        self.assertEqual('chunk one', stream.next())
2365
        self.assertEqual('chunk two', stream.next())
2366
        exc = self.assertRaises(errors.ErrorFromSmartServer, stream.next)
2367
        self.assertEqual(('error', 'abc'), exc.error_tuple)
2368
2369
3245.4.49 by Andrew Bennetts
Distinguish between errors in decoding a message into message parts from errors in handling decoded message parts, and use that to make sure that entire requests are read even when they result in exceptions.
2370
class TestMessageHandlerErrors(tests.TestCase):
2371
    """Tests for v3 that unrecognised (but well-formed) requests/responses are
2372
    still fully read off the wire, so that subsequent requests/responses on the
2373
    same medium can be decoded.
2374
    """
2375
2376
    def test_non_conventional_request(self):
2377
        """ConventionalRequestHandler (the default message handler on the
2378
        server side) will reject an unconventional message, but still consume
2379
        all the bytes of that message and signal when it has done so.
2380
2381
        This is what allows a server to continue to accept requests after the
2382
        client sends a completely unrecognised request.
2383
        """
2384
        # Define an invalid request (but one that is a well-formed message).
2385
        # This particular invalid request not only lacks the mandatory
2386
        # verb+args tuple, it has a single-byte part, which is forbidden.  In
2387
        # fact it has that part twice, to trigger multiple errors.
2388
        invalid_request = (
2389
            protocol.MESSAGE_VERSION_THREE +  # protocol version marker
2390
            '\0\0\0\x02de' + # empty headers
2391
            'oX' + # a single byte part: 'X'.  ConventionalRequestHandler will
2392
                   # error at this part.
2393
            'oX' + # and again.
2394
            'e' # end of message
2395
            )
2396
2397
        to_server = StringIO(invalid_request)
2398
        from_server = StringIO()
2399
        transport = memory.MemoryTransport('memory:///')
2400
        server = medium.SmartServerPipeStreamMedium(
2401
            to_server, from_server, transport)
2402
        proto = server._build_protocol()
2403
        message_handler = proto.message_handler
2404
        server._serve_one_request(proto)
2405
        # All the bytes have been read from the medium...
2406
        self.assertEqual('', to_server.read())
2407
        # ...and the protocol decoder has consumed all the bytes, and has
2408
        # finished reading.
2409
        self.assertEqual('', proto.unused_data)
2410
        self.assertEqual(0, proto.next_read_size())
2411
2412
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2413
class InstrumentedRequestHandler(object):
2414
    """Test Double of SmartServerRequestHandler."""
2415
2416
    def __init__(self):
2417
        self.calls = []
2418
2419
    def body_chunk_received(self, chunk_bytes):
2420
        self.calls.append(('body_chunk_received', chunk_bytes))
2421
2422
    def no_body_received(self):
2423
        self.calls.append(('no_body_received',))
2424
2425
    def prefixed_body_received(self, body_bytes):
2426
        self.calls.append(('prefixed_body_received', body_bytes))
2427
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
2428
    def end_received(self):
2429
        self.calls.append(('end_received',))
2430
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2431
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2432
class StubRequest(object):
2433
2434
    def finished_reading(self):
2435
        pass
2436
2437
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2438
class TestClientDecodingProtocolThree(TestSmartProtocol):
2439
    """Tests for v3 of the client-side protocol decoding."""
2440
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2441
    def make_logging_response_decoder(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2442
        """Make v3 response decoder using a test response handler."""
2443
        response_handler = LoggingMessageHandler()
2444
        decoder = protocol.ProtocolThreeDecoder(response_handler)
2445
        return decoder, response_handler
2446
2447
    def make_conventional_response_decoder(self):
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2448
        """Make v3 response decoder using a conventional response handler."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2449
        response_handler = message.ConventionalResponseHandler()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2450
        decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2451
        response_handler.setProtoAndMediumRequest(decoder, StubRequest())
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2452
        return decoder, response_handler
2453
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2454
    def test_trivial_response_decoding(self):
2455
        """Smoke test for the simplest possible v3 response: empty headers,
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2456
        status byte, empty args, no body.
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2457
        """
2458
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2459
        response_status = 'oS' # success
2460
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2461
        end = 'e' # end marker
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2462
        message_bytes = headers + response_status + args + end
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2463
        decoder, response_handler = self.make_logging_response_decoder()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2464
        decoder.accept_bytes(message_bytes)
2465
        # The protocol decoder has finished, and consumed all bytes
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2466
        self.assertEqual(0, decoder.next_read_size())
2467
        self.assertEqual('', decoder.unused_data)
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2468
        # The message handler has been invoked with all the parts of the
2469
        # trivial response: empty headers, status byte, no args, end.
2470
        self.assertEqual(
2471
            [('headers', {}), ('byte', 'S'), ('structure', []), ('end',)],
2472
            response_handler.event_log)
3195.3.5 by Andrew Bennetts
Start writing the client-side protocol logic for HPSS v3.
2473
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2474
    def test_incomplete_message(self):
2475
        """A decoder will keep signalling that it needs more bytes via
2476
        next_read_size() != 0 until it has seen a complete message, regardless
2477
        which state it is in.
2478
        """
2479
        # Define a simple response that uses all possible message parts.
2480
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2481
        response_status = 'oS' # success
2482
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2483
        body = 'b\0\0\0\x04BODY' # a body: 'BODY'
2484
        end = 'e' # end marker
2485
        simple_response = headers + response_status + args + body + end
2486
        # Feed the request to the decoder one byte at a time.
2487
        decoder, response_handler = self.make_logging_response_decoder()
2488
        for byte in simple_response:
2489
            self.assertNotEqual(0, decoder.next_read_size())
2490
            decoder.accept_bytes(byte)
2491
        # Now the response is complete
2492
        self.assertEqual(0, decoder.next_read_size())
2493
2494
    def test_read_response_tuple_raises_UnknownSmartMethod(self):
2495
        """read_response_tuple raises UnknownSmartMethod if the server replied
2496
        with 'UnknownMethod'.
2497
        """
3245.4.35 by Andrew Bennetts
Remove some commented out cruft, test (and fix) handling of an 'UnknownMethod' response.
2498
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2499
        response_status = 'oE' # error flag
2500
        # args: ('UnknownMethod', 'method-name')
2501
        args = 's\0\0\0\x20l13:UnknownMethod11:method-namee'
2502
        end = 'e' # end marker
2503
        message_bytes = headers + response_status + args + end
2504
        decoder, response_handler = self.make_conventional_response_decoder()
2505
        decoder.accept_bytes(message_bytes)
2506
        error = self.assertRaises(
2507
            errors.UnknownSmartMethod, response_handler.read_response_tuple)
2508
        self.assertEqual('method-name', error.verb)
2509
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2510
    def test_read_response_tuple_error(self):
2511
        """If the response has an error, it is raised as an exception."""
2512
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2513
        response_status = 'oE' # error
2514
        args = 's\0\0\0\x1al9:first arg10:second arge' # two args
2515
        end = 'e' # end marker
2516
        message_bytes = headers + response_status + args + end
2517
        decoder, response_handler = self.make_conventional_response_decoder()
2518
        decoder.accept_bytes(message_bytes)
2519
        error = self.assertRaises(
2520
            errors.ErrorFromSmartServer, response_handler.read_response_tuple)
2521
        self.assertEqual(('first arg', 'second arg'), error.error_tuple)
2522
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2523
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2524
class TestClientEncodingProtocolThree(TestSmartProtocol):
2525
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2526
    request_encoder = protocol.ProtocolThreeRequester
2527
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2528
    server_protocol_class = protocol.ProtocolThreeDecoder
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2529
2530
    def make_client_encoder_and_output(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2531
        result = self.make_client_protocol_and_output()
2532
        requester, response_handler, output = result
2533
        return requester, output
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2534
2535
    def test_call_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2536
        """A smoke test for ProtocolThreeRequester.call.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2537
2538
        This test checks that a particular simple invocation of call emits the
2539
        correct bytes for that invocation.
2540
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2541
        requester, output = self.make_client_encoder_and_output()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2542
        requester.set_headers({'header name': 'header value'})
2543
        requester.call('one arg')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2544
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2545
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2546
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2547
            's\x00\x00\x00\x0bl7:one arge' # args
2548
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2549
            output.getvalue())
2550
2551
    def test_call_with_body_bytes_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2552
        """A smoke test for ProtocolThreeRequester.call_with_body_bytes.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2553
2554
        This test checks that a particular simple invocation of
2555
        call_with_body_bytes emits the correct bytes for that invocation.
2556
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2557
        requester, output = self.make_client_encoder_and_output()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2558
        requester.set_headers({'header name': 'header value'})
2559
        requester.call_with_body_bytes(('one arg',), 'body bytes')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2560
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2561
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2562
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2563
            's\x00\x00\x00\x0bl7:one arge' # args
2564
            'b' # there is a prefixed body
2565
            '\x00\x00\x00\nbody bytes' # the prefixed body
2566
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2567
            output.getvalue())
2568
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2569
    def test_call_writes_just_once(self):
2570
        """A bodyless request is written to the medium all at once."""
2571
        medium_request = StubMediumRequest()
2572
        encoder = protocol.ProtocolThreeRequester(medium_request)
2573
        encoder.call('arg1', 'arg2', 'arg3')
2574
        self.assertEqual(
2575
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2576
2577
    def test_call_with_body_bytes_writes_just_once(self):
2578
        """A request with body bytes is written to the medium all at once."""
2579
        medium_request = StubMediumRequest()
2580
        encoder = protocol.ProtocolThreeRequester(medium_request)
2581
        encoder.call_with_body_bytes(('arg', 'arg'), 'body bytes')
2582
        self.assertEqual(
2583
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2584
2585
2586
class StubMediumRequest(object):
2587
    """A stub medium request that tracks the number of times accept_bytes is
2588
    called.
2589
    """
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2590
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2591
    def __init__(self):
2592
        self.calls = []
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
2593
        self._medium = 'dummy medium'
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2594
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2595
    def accept_bytes(self, bytes):
2596
        self.calls.append('accept_bytes')
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2597
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2598
    def finished_writing(self):
2599
        self.calls.append('finished_writing')
2600
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2601
3245.4.37 by Andrew Bennetts
Add test for sending ProtocolThreeResponder.send_error(UnknownSmartMethod(...)).
2602
class TestResponseEncodingProtocolThree(tests.TestCase):
2603
2604
    def make_response_encoder(self):
2605
        out_stream = StringIO()
2606
        response_encoder = protocol.ProtocolThreeResponder(out_stream.write)
2607
        return response_encoder, out_stream
2608
2609
    def test_send_error_unknown_method(self):
2610
        encoder, out_stream = self.make_response_encoder()
2611
        encoder.send_error(errors.UnknownSmartMethod('method name'))
2612
        # Use assertEndsWith so that we don't compare the header, which varies
2613
        # by bzrlib.__version__.
2614
        self.assertEndsWith(
2615
            out_stream.getvalue(),
2616
            # error status
2617
            'oE' +
2618
            # tuple: 'UnknownMethod', 'method name'
2619
            's\x00\x00\x00\x20l13:UnknownMethod11:method namee'
2620
            # end of message
2621
            'e')
2622
2623
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2624
class TestResponseEncoderBufferingProtocolThree(tests.TestCase):
2625
    """Tests for buffering of responses.
2626
2627
    We want to avoid doing many small writes when one would do, to avoid
2628
    unnecessary network overhead.
2629
    """
2630
2631
    def setUp(self):
2632
        self.writes = []
2633
        self.responder = protocol.ProtocolThreeResponder(self.writes.append)
2634
2635
    def assertWriteCount(self, expected_count):
2636
        self.assertEqual(
2637
            expected_count, len(self.writes),
2638
            "Too many writes: %r" % (self.writes,))
2639
        
2640
    def test_send_error_writes_just_once(self):
2641
        """An error response is written to the medium all at once."""
2642
        self.responder.send_error(Exception('An exception string.'))
2643
        self.assertWriteCount(1)
2644
2645
    def test_send_response_writes_just_once(self):
2646
        """A normal response with no body is written to the medium all at once.
2647
        """
2648
        response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
2649
        self.responder.send_response(response)
2650
        self.assertWriteCount(1)
2651
2652
    def test_send_response_with_body_writes_just_once(self):
2653
        """A normal response with a monolithic body is written to the medium
2654
        all at once.
2655
        """
2656
        response = _mod_request.SuccessfulSmartServerResponse(
2657
            ('arg', 'arg'), body='body bytes')
2658
        self.responder.send_response(response)
2659
        self.assertWriteCount(1)
2660
2661
    def test_send_response_with_body_stream_writes_once_per_chunk(self):
2662
        """A normal response with a stream body is written to the medium
2663
        writes to the medium once per chunk.
2664
        """
2665
        # Construct a response with stream with 2 chunks in it.
2666
        response = _mod_request.SuccessfulSmartServerResponse(
2667
            ('arg', 'arg'), body_stream=['chunk1', 'chunk2'])
2668
        self.responder.send_response(response)
2669
        # We will write 3 times: exactly once for each chunk, plus a final
2670
        # write to end the response.
2671
        self.assertWriteCount(3)
2672
2673
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.
2674
class TestSmartClientUnicode(tests.TestCase):
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2675
    """_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.
2676
2677
    Unicode arguments to call_with_body_bytes are not correct (remote method
2678
    names, arguments, and bodies must all be expressed as byte strings), but
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2679
    _SmartClient should gracefully reject them, rather than getting into a
2680
    broken state that prevents future correct calls from working.  That is, it
2681
    should be possible to issue more requests on the medium afterwards, rather
2682
    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.
2683
    mysteriously fail with TooManyConcurrentRequests.
2684
    """
2685
2686
    def assertCallDoesNotBreakMedium(self, method, args, body):
2687
        """Call a medium with the given method, args and body, then assert that
2688
        the medium is left in a sane state, i.e. is capable of allowing further
2689
        requests.
2690
        """
2691
        input = StringIO("\n")
2692
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
2693
        client_medium = medium.SmartSimplePipesClientMedium(
2694
            input, output, 'ignored base')
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
2695
        smart_client = client._SmartClient(client_medium)
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.
2696
        self.assertRaises(TypeError,
2697
            smart_client.call_with_body_bytes, method, args, body)
2698
        self.assertEqual("", output.getvalue())
2699
        self.assertEqual(None, client_medium._current_request)
2700
2701
    def test_call_with_body_bytes_unicode_method(self):
2702
        self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
2703
2704
    def test_call_with_body_bytes_unicode_args(self):
2705
        self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
2414.1.2 by Andrew Bennetts
Deal with review comments.
2706
        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.
2707
2708
    def test_call_with_body_bytes_unicode_body(self):
2709
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
2710
2711
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2712
class MockMedium(object):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2713
    """A mock medium that can be used to test _SmartClient.
2714
    
2715
    It can be given a series of requests to expect (and responses it should
2716
    return for them).  It can also be told when the client is expected to
2717
    disconnect a medium.  Expectations must be satisfied in the order they are
2718
    given, or else an AssertionError will be raised.
2719
2720
    Typical use looks like::
2721
2722
        medium = MockMedium()
2723
        medium.expect_request(...)
2724
        medium.expect_request(...)
2725
        medium.expect_request(...)
2726
    """
2727
2728
    def __init__(self):
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2729
        self.base = 'dummy base'
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2730
        self._mock_request = _MockMediumRequest(self)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2731
        self._expected_events = []
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
2732
        self._protocol_version = None
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2733
        
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2734
    def expect_request(self, request_bytes, response_bytes,
2735
                       allow_partial_read=False):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2736
        """Expect 'request_bytes' to be sent, and reply with 'response_bytes'.
2737
2738
        No assumption is made about how many times accept_bytes should be
2739
        called to send the request.  Similarly, no assumption is made about how
2740
        many times read_bytes/read_line are called by protocol code to read a
2741
        response.  e.g.::
2742
        
2743
            request.accept_bytes('ab')
2744
            request.accept_bytes('cd')
2745
            request.finished_writing()
2746
2747
        and::
2748
        
2749
            request.accept_bytes('abcd')
2750
            request.finished_writing()
2751
2752
        Will both satisfy ``medium.expect_request('abcd', ...)``.  Thus tests
2753
        using this should not break due to irrelevant changes in protocol
2754
        implementations.
2755
2756
        :param allow_partial_read: if True, no assertion is raised if a
2757
            response is not fully read.  Setting this is useful when the client
2758
            is expected to disconnect without needing to read the complete
2759
            response.  Default is False.
2760
        """
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2761
        self._expected_events.append(('send request', request_bytes))
2762
        if allow_partial_read:
2763
            self._expected_events.append(
2764
                ('read response (partial)', response_bytes))
2765
        else:
2766
            self._expected_events.append(('read response', response_bytes))
2767
2768
    def expect_disconnect(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2769
        """Expect the client to call ``medium.disconnect()``."""
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2770
        self._expected_events.append('disconnect')
2771
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2772
    def _assertEvent(self, observed_event):
2773
        """Raise AssertionError unless observed_event matches the next expected
2774
        event.
2775
2776
        :seealso: expect_request
2777
        :seealso: expect_disconnect
2778
        """
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2779
        try:
2780
            expected_event = self._expected_events.pop(0)
2781
        except IndexError:
2782
            raise AssertionError(
2783
                'Mock medium observed event %r, but no more events expected'
2784
                % (observed_event,))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2785
        if expected_event[0] == 'read response (partial)':
2786
            if observed_event[0] != 'read response':
2787
                raise AssertionError(
2788
                    'Mock medium observed event %r, but expected event %r'
2789
                    % (observed_event, expected_event))
2790
        elif observed_event != expected_event:
2791
            raise AssertionError(
2792
                'Mock medium observed event %r, but expected event %r'
2793
                % (observed_event, expected_event))
2794
        if self._expected_events:
2795
            next_event = self._expected_events[0]
2796
            if next_event[0].startswith('read response'):
2797
                self._mock_request._response = next_event[1]
2798
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2799
    def get_request(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2800
        return self._mock_request
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2801
2802
    def disconnect(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2803
        if self._mock_request._read_bytes:
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2804
            self._assertEvent(('read response', self._mock_request._read_bytes))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2805
            self._mock_request._read_bytes = ''
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2806
        self._assertEvent('disconnect')
2807
2808
2809
class _MockMediumRequest(object):
2810
    """A mock ClientMediumRequest used by MockMedium."""
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2811
2812
    def __init__(self, mock_medium):
2813
        self._medium = mock_medium
2814
        self._written_bytes = ''
2815
        self._read_bytes = ''
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2816
        self._response = None
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2817
2818
    def accept_bytes(self, bytes):
2819
        self._written_bytes += bytes
2820
2821
    def finished_writing(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2822
        self._medium._assertEvent(('send request', self._written_bytes))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2823
        self._written_bytes = ''
2824
2825
    def finished_reading(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2826
        self._medium._assertEvent(('read response', self._read_bytes))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2827
        self._read_bytes = ''
2828
2829
    def read_bytes(self, size):
2830
        resp = self._response
2831
        bytes, resp = resp[:size], resp[size:]
2832
        self._response = resp
2833
        self._read_bytes += bytes
2834
        return bytes
2835
2836
    def read_line(self):
2837
        resp = self._response
2838
        try:
2839
            line, resp = resp.split('\n', 1)
2840
            line += '\n'
2841
        except ValueError:
2842
            line, resp = resp, ''
2843
        self._response = resp
2844
        self._read_bytes += line
2845
        return line
2846
2847
2848
class Test_SmartClientVersionDetection(tests.TestCase):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2849
    """Tests for _SmartClient's automatic protocol version detection.
2850
2851
    On the first remote call, _SmartClient will keep retrying the request with
2852
    different protocol versions until it finds one that works.
2853
    """
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2854
2855
    def test_version_three_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2856
        """With a protocol 3 server, only one request is needed."""
2857
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
2858
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2859
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
2860
        medium.expect_request(
2861
            message_start +
2862
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
2863
            message_start + 's\0\0\0\x13l14:response valueee')
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2864
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2865
        # The call succeeded without raising any exceptions from the mock
2866
        # medium, and the smart_client returns the response from the server.
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2867
        self.assertEqual(('response value',), result)
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2868
        self.assertEqual([], medium._expected_events)
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2869
2870
    def test_version_two_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2871
        """If the server only speaks protocol 2, the client will first try
2872
        version 3, then fallback to protocol 2.
2873
2874
        Further, _SmartClient caches the detection, so future requests will all
2875
        use protocol 2 immediately.
2876
        """
2877
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
2878
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2879
        # First the client should send a v3 request, but the server will reply
2880
        # with a v2 error.
2881
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2882
            'bzr message 3 (bzr 1.6)\n\x00\x00\x00\x02de' +
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2883
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
2884
            'bzr response 2\nfailed\n\n')
2885
        # So then the client should disconnect to reset the connection, because
2886
        # the client needs to assume the server cannot read any further
2887
        # requests off the original connection.
2888
        medium.expect_disconnect()
2889
        # The client should then retry the original request in v2
2890
        medium.expect_request(
2891
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
2892
            'bzr response 2\nsuccess\nresponse value\n')
2893
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
2894
        # The smart_client object will return the result of the successful
2895
        # query.
2896
        self.assertEqual(('response value',), result)
2897
2898
        # Now try another request, and this time the client will just use
2899
        # protocol 2.  (i.e. the autodetection won't be repeated)
2900
        medium.expect_request(
2901
            'bzr request 2\nanother-method\n',
2902
            'bzr response 2\nsuccess\nanother response\n')
2903
        result = smart_client.call('another-method')
2904
        self.assertEqual(('another response',), result)
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2905
        self.assertEqual([], medium._expected_events)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2906
2907
    def test_unknown_version(self):
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2908
        """If the server does not use any known (or at least supported)
2909
        protocol version, a SmartProtocolError is raised.
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2910
        """
2911
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
2912
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2913
        unknown_protocol_bytes = 'Unknown protocol!'
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2914
        # The client will try v3 and v2 before eventually giving up.
2915
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2916
            'bzr message 3 (bzr 1.6)\n\x00\x00\x00\x02de' +
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2917
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
2918
            unknown_protocol_bytes)
2919
        medium.expect_disconnect()
2920
        medium.expect_request(
2921
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
2922
            unknown_protocol_bytes)
2923
        medium.expect_disconnect()
2924
        self.assertRaises(
2925
            errors.SmartProtocolError,
2926
            smart_client.call, 'method-name', 'arg 1', 'arg 2')
2927
        self.assertEqual([], medium._expected_events)
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
2928
2929
    def test_first_response_is_error(self):
2930
        """If the server replies with an error, then the version detection
2931
        should be complete.
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
2932
        
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
2933
        This test is very similar to test_version_two_server, but catches a bug
2934
        we had in the case where the first reply was an error response.
2935
        """
2936
        medium = MockMedium()
2937
        smart_client = client._SmartClient(medium, headers={})
2938
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
2939
        # Issue a request that gets an error reply in a non-default protocol
2940
        # version.
2941
        medium.expect_request(
2942
            message_start +
2943
            's\x00\x00\x00\x10l11:method-nameee',
2944
            'bzr response 2\nfailed\n\n')
2945
        medium.expect_disconnect()
2946
        medium.expect_request(
2947
            'bzr request 2\nmethod-name\n',
2948
            'bzr response 2\nfailed\nFooBarError\n')
2949
        err = self.assertRaises(
2950
            errors.ErrorFromSmartServer,
2951
            smart_client.call, 'method-name')
2952
        self.assertEqual(('FooBarError',), err.error_tuple)
2953
        # Now the medium should have remembered the protocol version, so
2954
        # subsequent requests will use the remembered version immediately.
2955
        medium.expect_request(
2956
            'bzr request 2\nmethod-name\n',
2957
            'bzr response 2\nsuccess\nresponse value\n')
2958
        result = smart_client.call('method-name')
2959
        self.assertEqual(('response value',), result)
2960
        self.assertEqual([], medium._expected_events)
2961
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2962
2963
class Test_SmartClient(tests.TestCase):
2964
2965
    def test_call_default_headers(self):
2966
        """ProtocolThreeRequester.call by default sends a 'Software
2967
        version' header.
2968
        """
3431.3.4 by Andrew Bennetts
Revert now unnecessary test change from bzr.dev.
2969
        smart_client = client._SmartClient('dummy medium')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2970
        self.assertEqual(
2971
            bzrlib.__version__, smart_client._headers['Software version'])
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
2972
        # XXX: need a test that smart_client._headers is passed to the request
2973
        # encoder.
2974
2975
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2976
class LengthPrefixedBodyDecoder(tests.TestCase):
2977
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2978
    # XXX: TODO: make accept_reading_trailer invoke translate_response or 
2979
    # something similar to the ProtocolBase method.
2980
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2981
    def test_construct(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2982
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2983
        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.
2984
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2985
        self.assertEqual('', decoder.read_pending_data())
2986
        self.assertEqual('', decoder.unused_data)
2987
2988
    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
2989
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2990
        decoder.accept_bytes('')
2991
        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.
2992
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2993
        self.assertEqual('', decoder.read_pending_data())
2994
        self.assertEqual('', decoder.unused_data)
2995
        decoder.accept_bytes('7')
2996
        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.
2997
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2998
        self.assertEqual('', decoder.read_pending_data())
2999
        self.assertEqual('', decoder.unused_data)
3000
        decoder.accept_bytes('\na')
3001
        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.
3002
        self.assertEqual(11, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3003
        self.assertEqual('a', decoder.read_pending_data())
3004
        self.assertEqual('', decoder.unused_data)
3005
        decoder.accept_bytes('bcdefgd')
3006
        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.
3007
        self.assertEqual(4, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3008
        self.assertEqual('bcdefg', decoder.read_pending_data())
3009
        self.assertEqual('', decoder.unused_data)
3010
        decoder.accept_bytes('one')
3011
        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.
3012
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3013
        self.assertEqual('', decoder.read_pending_data())
3014
        self.assertEqual('', decoder.unused_data)
3015
        decoder.accept_bytes('\nblarg')
3016
        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.
3017
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3018
        self.assertEqual('', decoder.read_pending_data())
3019
        self.assertEqual('blarg', decoder.unused_data)
3020
        
3021
    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
3022
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3023
        decoder.accept_bytes('1\nadone\nunused')
3024
        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.
3025
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3026
        self.assertEqual('a', decoder.read_pending_data())
3027
        self.assertEqual('unused', decoder.unused_data)
3028
3029
    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
3030
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3031
        decoder.accept_bytes('1\na')
3032
        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.
3033
        self.assertEqual(5, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3034
        self.assertEqual('a', decoder.read_pending_data())
3035
        self.assertEqual('', decoder.unused_data)
3036
        decoder.accept_bytes('done\n')
3037
        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.
3038
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3039
        self.assertEqual('', decoder.read_pending_data())
3040
        self.assertEqual('', decoder.unused_data)
3041
3042
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3043
class TestChunkedBodyDecoder(tests.TestCase):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3044
    """Tests for ChunkedBodyDecoder.
3045
    
3046
    This is the body decoder used for protocol version two.
3047
    """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3048
3049
    def test_construct(self):
3050
        decoder = protocol.ChunkedBodyDecoder()
3051
        self.assertFalse(decoder.finished_reading)
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3052
        self.assertEqual(8, decoder.next_read_size())
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3053
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3054
        self.assertEqual('', decoder.unused_data)
3055
3056
    def test_empty_content(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3057
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
3058
        """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3059
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3060
        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.
3061
        decoder.accept_bytes('END\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3062
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3063
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3064
        self.assertEqual('', decoder.unused_data)
3065
3066
    def test_one_chunk(self):
3067
        """A body in a single chunk is decoded correctly."""
3068
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3069
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3070
        chunk_length = 'f\n'
3071
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3072
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3073
        decoder.accept_bytes(chunk_length + chunk_content + finish)
3074
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3075
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3076
        self.assertEqual('', decoder.unused_data)
3077
        
3078
    def test_incomplete_chunk(self):
3079
        """When there are less bytes in the chunk than declared by the length,
3080
        then we haven't finished reading yet.
3081
        """
3082
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3083
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3084
        chunk_length = '8\n'
3085
        three_bytes = '123'
3086
        decoder.accept_bytes(chunk_length + three_bytes)
3087
        self.assertFalse(decoder.finished_reading)
3088
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3089
            5 + 4, decoder.next_read_size(),
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3090
            "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.
3091
            "this chunk plus 4 (the length of the end-of-body marker: "
3092
            "'END\\n')")
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3093
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3094
3095
    def test_incomplete_length(self):
3096
        """A chunk length hasn't been read until a newline byte has been read.
3097
        """
3098
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3099
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3100
        decoder.accept_bytes('9')
3101
        self.assertEqual(
3102
            1, decoder.next_read_size(),
3103
            "The next_read_size hint should be 1, because we don't know the "
3104
            "length yet.")
3105
        decoder.accept_bytes('\n')
3106
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3107
            9 + 4, decoder.next_read_size(),
3108
            "The next_read_size hint should be the length of the chunk plus 4 "
3109
            "(the length of the end-of-body marker: 'END\\n')")
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3110
        self.assertFalse(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3111
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3112
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3113
    def test_two_chunks(self):
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3114
        """Content from multiple chunks is concatenated."""
3115
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3116
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3117
        chunk_one = '3\naaa'
3118
        chunk_two = '5\nbbbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3119
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3120
        decoder.accept_bytes(chunk_one + chunk_two + finish)
3121
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3122
        self.assertEqual('aaa', decoder.read_next_chunk())
3123
        self.assertEqual('bbbbb', decoder.read_next_chunk())
3124
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3125
        self.assertEqual('', decoder.unused_data)
3126
3127
    def test_excess_bytes(self):
3128
        """Bytes after the chunked body are reported as unused bytes."""
3129
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3130
        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.
3131
        chunked_body = "5\naaaaaEND\n"
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3132
        excess_bytes = "excess bytes"
3133
        decoder.accept_bytes(chunked_body + excess_bytes)
3134
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3135
        self.assertEqual('aaaaa', decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3136
        self.assertEqual(excess_bytes, decoder.unused_data)
3137
        self.assertEqual(
3138
            1, decoder.next_read_size(),
3139
            "next_read_size hint should be 1 when finished_reading.")
3140
3141
    def test_multidigit_length(self):
3142
        """Lengths in the chunk prefixes can have multiple digits."""
3143
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3144
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3145
        length = 0x123
3146
        chunk_prefix = hex(length) + '\n'
3147
        chunk_bytes = 'z' * length
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3148
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3149
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
3150
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3151
        self.assertEqual(chunk_bytes, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3152
3153
    def test_byte_at_a_time(self):
3154
        """A complete body fed to the decoder one byte at a time should not
3155
        confuse the decoder.  That is, it should give the same result as if the
3156
        bytes had been received in one batch.
3157
3158
        This test is the same as test_one_chunk apart from the way accept_bytes
3159
        is called.
3160
        """
3161
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3162
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3163
        chunk_length = 'f\n'
3164
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3165
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3166
        for byte in (chunk_length + chunk_content + finish):
3167
            decoder.accept_bytes(byte)
3168
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3169
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3170
        self.assertEqual('', decoder.unused_data)
3171
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3172
    def test_read_pending_data_resets(self):
3173
        """read_pending_data does not return the same bytes twice."""
3174
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3175
        decoder.accept_bytes('chunked\n')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3176
        chunk_one = '3\naaa'
3177
        chunk_two = '3\nbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3178
        finish = 'END\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3179
        decoder.accept_bytes(chunk_one)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3180
        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.
3181
        decoder.accept_bytes(chunk_two)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3182
        self.assertEqual('bbb', decoder.read_next_chunk())
3183
        self.assertEqual(None, decoder.read_next_chunk())
3184
3185
    def test_decode_error(self):
3186
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3187
        decoder.accept_bytes('chunked\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3188
        chunk_one = 'b\nfirst chunk'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3189
        error_signal = 'ERR\n'
3190
        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.
3191
        finish = 'END\n'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3192
        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.
3193
        self.assertTrue(decoder.finished_reading)
3194
        self.assertEqual('first chunk', decoder.read_next_chunk())
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3195
        expected_failure = _mod_request.FailedSmartServerResponse(
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3196
            ('part1', 'part2'))
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3197
        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.
3198
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3199
    def test_bad_header(self):
3200
        """accept_bytes raises a SmartProtocolError if a chunked body does not
3201
        start with the right header.
3202
        """
3203
        decoder = protocol.ChunkedBodyDecoder()
3204
        self.assertRaises(
3205
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
3206
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3207
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3208
class TestSuccessfulSmartServerResponse(tests.TestCase):
3209
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3210
    def test_construct_no_body(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3211
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3212
        self.assertEqual(('foo', 'bar'), response.args)
3213
        self.assertEqual(None, response.body)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3214
3215
    def test_construct_with_body(self):
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3216
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'),
3217
                                                              'bytes')
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3218
        self.assertEqual(('foo', 'bar'), response.args)
3219
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
3220
        # repr(response) doesn't trigger exceptions.
3221
        repr(response)
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3222
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3223
    def test_construct_with_body_stream(self):
3224
        bytes_iterable = ['abc']
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3225
        response = _mod_request.SuccessfulSmartServerResponse(
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3226
            ('foo', 'bar'), body_stream=bytes_iterable)
3227
        self.assertEqual(('foo', 'bar'), response.args)
3228
        self.assertEqual(bytes_iterable, response.body_stream)
3229
3230
    def test_construct_rejects_body_and_body_stream(self):
3231
        """'body' and 'body_stream' are mutually exclusive."""
3232
        self.assertRaises(
3233
            errors.BzrError,
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3234
            _mod_request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3235
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3236
    def test_is_successful(self):
3237
        """is_successful should return True for SuccessfulSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3238
        response = _mod_request.SuccessfulSmartServerResponse(('error',))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3239
        self.assertEqual(True, response.is_successful())
3240
3241
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3242
class TestFailedSmartServerResponse(tests.TestCase):
3243
3244
    def test_construct(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3245
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3246
        self.assertEqual(('foo', 'bar'), response.args)
3247
        self.assertEqual(None, response.body)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3248
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3249
        self.assertEqual(('foo', 'bar'), response.args)
3250
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
3251
        # repr(response) doesn't trigger exceptions.
3252
        repr(response)
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3253
3254
    def test_is_successful(self):
3255
        """is_successful should return False for FailedSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3256
        response = _mod_request.FailedSmartServerResponse(('error',))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3257
        self.assertEqual(False, response.is_successful())
3258
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3259
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3260
class FakeHTTPMedium(object):
3261
    def __init__(self):
3262
        self.written_request = None
3263
        self._current_request = None
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
3264
    def send_http_smart_request(self, bytes):
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3265
        self.written_request = bytes
3266
        return None
3267
3268
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
3269
class HTTPTunnellingSmokeTest(tests.TestCase):
3270
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)
3271
    def setUp(self):
3272
        super(HTTPTunnellingSmokeTest, self).setUp()
3273
        # We use the VFS layer as part of HTTP tunnelling tests.
2402.1.2 by Andrew Bennetts
Deal with review comments.
3274
        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)
3275
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3276
    def test_smart_http_medium_request_accept_bytes(self):
3277
        medium = FakeHTTPMedium()
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
3278
        request = SmartClientHTTPMediumRequest(medium)
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3279
        request.accept_bytes('abc')
3280
        request.accept_bytes('def')
3281
        self.assertEqual(None, medium.written_request)
3282
        request.finished_writing()
3283
        self.assertEqual('abcdef', medium.written_request)
3284
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.
3285
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
3286
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.
3287
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
3288
    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.
3289
        # 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')).
3290
        # requests for child URLs of that to the original URL.  i.e., we want to
3291
        # POST to "bzr+http://host/foo/.bzr/smart" and never something like
3292
        # "bzr+http://host/foo/.bzr/branch/.bzr/smart".  So, a cloned
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
3293
        # 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.
3294
        # it sends in smart requests accordingly.
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
3295
        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.
3296
        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')).
3297
        self.assertEqual(base_transport._http_transport,
3298
                         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.
3299
        self.assertEqual('child_dir/foo', new_transport._remote_path('foo'))
3431.3.8 by Andrew Bennetts
Add two tests that fail without the fixes in this branch.
3300
        self.assertEqual(
3301
            'child_dir/',
3302
            new_transport._client.remote_path_from_transport(new_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.
3303
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
3304
    def test_remote_path_unnormal_base(self):
3305
        # If the transport's base isn't normalised, the _remote_path should
3306
        # still be calculated correctly.
3307
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
3308
        self.assertEqual('c', base_transport._remote_path('c'))
3309
3310
    def test_clone_unnormal_base(self):
3311
        # If the transport's base isn't normalised, cloned transports should
3312
        # still work correctly.
3313
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
3314
        new_transport = base_transport.clone('c')
3315
        self.assertEqual('bzr+http://host/%7Ea/b/c/', new_transport.base)
3431.3.8 by Andrew Bennetts
Add two tests that fail without the fixes in this branch.
3316
        self.assertEqual(
3317
            'c/',
3318
            new_transport._client.remote_path_from_transport(new_transport))
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
3319
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3320
        
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
3321
# TODO: Client feature that does get_bundle and then installs that into a
3322
# branch; this can be used in place of the regular pull/fetch operation when
3323
# coming from a smart server.
3324
#
3325
# TODO: Eventually, want to do a 'branch' command by fetching the whole
3326
# history as one big bundle.  How?  
3327
#
3328
# The branch command does 'br_from.sprout', which tries to preserve the same
3329
# format.  We don't necessarily even want that.  
3330
#
3331
# It might be simpler to handle cmd_pull first, which does a simpler fetch()
3332
# operation from one branch into another.  It already has some code for
3333
# pulling from a bundle, which it does by trying to see if the destination is
3334
# a bundle file.  So it seems the logic for pull ought to be:
3335
# 
3336
#  - if it's a smart server, get a bundle from there and install that
3337
#  - if it's a bundle, install that
3338
#  - if it's a branch, pull from there
3339
#
3340
# Getting a bundle from a smart server is a bit different from reading a
3341
# bundle from a URL:
3342
#
3343
#  - we can reasonably remember the URL we last read from 
3344
#  - you can specify a revision number to pull, and we need to pass it across
3345
#    to the server as a limit on what will be requested
3346
#
3347
# TODO: Given a URL, determine whether it is a smart server or not (or perhaps
3348
# otherwise whether it's a bundle?)  Should this be a property or method of
3349
# the transport?  For the ssh protocol, we always know it's a smart server.
3350
# For http, we potentially need to probe.  But if we're explicitly given
3351
# bzr+http:// then we can skip that for now.