/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
1
# Copyright (C) 2006, 2007, 2008, 2009 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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
71
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
72
    def close(self):
73
        self.vendor.calls.append(('close', ))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
74
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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?
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
81
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
135
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
142
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
151
        # but it does support serial requests: we construct one after
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
173
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
200
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
215
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
216
    def test_simple_pipes_client_supports__flush(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
217
        # invoking _flush on a SimplePipesClient should flush the output
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
265
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
353
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
372
        # invoking _flush on a SSHClientMedium should flush the output
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
411
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
428
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
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.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
471
472
    SmartClientStreamMediumRequest is a helper for the three stream based
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
478
        # calling accept_bytes after calling finished_writing raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
540
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
544
        # and checking that the data is supplied. Its possible that a
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
569
        # calling read_bytes after calling finished_reading raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
607
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
635
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
646
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
726
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
818
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
859
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
860
    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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
870
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
871
    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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
921
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
962
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
970
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
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())
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
995
            err = self.assertRaises(errors.UnknownErrorFromSmartServer,
996
                transport.get, 'something')
997
            self.assertContainsRe(str(err), 'some random exception')
2018.5.171 by Andrew Bennetts
Disconnect RemoteTransports in some tests to avoid tripping up test_strace with leftover threads from previous tests.
998
            transport.disconnect()
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
999
        finally:
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
1000
            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
1001
1002
1003
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1004
    """Tests for connection/end to end behaviour using the TCP server.
1005
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1006
    All of these tests are run with a server running on another thread serving
1007
    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`.
1008
1009
    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
1010
    """
1011
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1012
    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`.
1013
        """Setup the server.
1014
1015
        :param readonly: Create a readonly server.
1016
        """
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1017
        if not backing_transport:
1018
            self.backing_transport = memory.MemoryTransport()
1019
        else:
1020
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1021
        if readonly:
1022
            self.real_backing_transport = self.backing_transport
1023
            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.
1024
        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.
1025
        self.server.start_background_thread('-' + self.id())
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1026
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1027
        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
1028
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1029
    def tearDownServer(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1030
        if getattr(self, 'transport', None):
1031
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1032
            del self.transport
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, 'server', None):
1034
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1035
            del self.server
1036
1037
1038
class TestServerSocketUsage(SmartTCPTests):
1039
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.
1040
    def test_server_setup_teardown(self):
1041
        """It should be safe to teardown the server with no requests."""
1042
        self.setUpServer()
1043
        server = self.server
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1044
        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.
1045
        self.tearDownServer()
1046
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1047
1048
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
1049
        """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
1050
        self.setUpServer()
2370.4.2 by Robert Collins
Review feedback.
1051
        server = self.server
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1052
        self.transport.has('.')
1053
        self.tearDownServer()
1054
        # if the listening socket has closed, we should get a BADFD error
1055
        # when connecting, rather than a hang.
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1056
        transport = remote.RemoteTCPTransport(server.get_url())
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1057
        self.assertRaises(errors.ConnectionError, transport.has, '.')
1058
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1059
1060
class WritableEndToEndTests(SmartTCPTests):
1061
    """Client to server tests that require a writable transport."""
1062
1063
    def setUp(self):
1064
        super(WritableEndToEndTests, self).setUp()
1065
        self.setUpServer()
1066
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1067
    def test_start_tcp_server(self):
1068
        url = self.server.get_url()
1069
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
1070
1071
    def test_smart_transport_has(self):
1072
        """Checking for file existence over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1073
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1074
        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
1075
        self.assertTrue(self.transport.has("foo"))
1076
        self.assertFalse(self.transport.has("non-foo"))
1077
1078
    def test_smart_transport_get(self):
1079
        """Read back a file over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1080
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1081
        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
1082
        fp = self.transport.get("foo")
1083
        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`.
1084
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1085
    def test_get_error_enoent(self):
1086
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
1087
        # The path in a raised NoSuchFile exception should be the precise path
1088
        # asked for by the client. This gives meaningful and unsurprising errors
1089
        # for users.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1090
        self._captureVar('BZR_NO_SMART_VFS', None)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1091
        err = self.assertRaises(
1092
            errors.NoSuchFile, self.transport.get, 'not%20a%20file')
1093
        self.assertEqual('not%20a%20file', err.path)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1094
1095
    def test_simple_clone_conn(self):
1096
        """Test that cloning reuses the same connection."""
1097
        # we create a real connection not a loopback one, but it will use the
1098
        # 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__.
1099
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1100
        self.assertIs(self.transport.get_smart_medium(),
1101
                      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
1102
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)
1103
    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
1104
        self.assertEquals('/foo/bar',
1105
                          self.transport._remote_path('foo/bar'))
1106
1107
    def test_clone_changes_base(self):
1108
        """Cloning transport produces one with a new base location"""
1109
        conn2 = self.transport.clone('subdir')
1110
        self.assertEquals(self.transport.base + 'subdir/',
1111
                          conn2.base)
1112
1113
    def test_open_dir(self):
1114
        """Test changing directory"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1115
        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
1116
        transport = self.transport
1117
        self.backing_transport.mkdir('toffee')
1118
        self.backing_transport.mkdir('toffee/apple')
1119
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1120
        toffee_trans = transport.clone('toffee')
1121
        # Check that each transport has only the contents of its directory
1122
        # directly visible. If state was being held in the wrong object, it's
1123
        # conceivable that cloning a transport would alter the state of the
1124
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1125
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1126
        self.assertFalse(toffee_trans.has('toffee'))
1127
        self.assertFalse(transport.has('apple'))
1128
        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
1129
1130
    def test_open_bzrdir(self):
1131
        """Open an existing bzrdir over smart transport"""
1132
        transport = self.transport
1133
        t = self.backing_transport
1134
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
1135
        result_dir = bzrdir.BzrDir.open_containing_from_transport(transport)
1136
1137
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1138
class ReadOnlyEndToEndTests(SmartTCPTests):
1139
    """Tests from the client to the server using a readonly backing transport."""
1140
1141
    def test_mkdir_error_readonly(self):
1142
        """TransportNotPossible should be preserved from the backing transport."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1143
        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`.
1144
        self.setUpServer(readonly=True)
1145
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1146
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1147
1148
1149
class TestServerHooks(SmartTCPTests):
1150
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1151
    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
1152
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1153
        self.hook_calls.append((backing_urls, public_url))
1154
1155
    def test_server_started_hook_memory(self):
1156
        """The server_started hook fires when the server is started."""
1157
        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.
1158
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1159
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1160
        self.setUpServer()
1161
        # at this point, the server will be starting a thread up.
1162
        # there is no indicator at the moment, so bodge it by doing a request.
1163
        self.transport.has('.')
1164
        # The default test server uses MemoryTransport and that has no external
1165
        # url:
1166
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1167
            self.hook_calls)
1168
1169
    def test_server_started_hook_file(self):
1170
        """The server_started hook fires when the server is started."""
1171
        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.
1172
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1173
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1174
        self.setUpServer(backing_transport=get_transport("."))
1175
        # at this point, the server will be starting a thread up.
1176
        # there is no indicator at the moment, so bodge it by doing a request.
1177
        self.transport.has('.')
1178
        # The default test server uses MemoryTransport and that has no external
1179
        # url:
1180
        self.assertEqual([([
1181
            self.backing_transport.base, self.backing_transport.external_url()],
1182
             self.transport.base)],
1183
            self.hook_calls)
1184
1185
    def test_server_stopped_hook_simple_memory(self):
1186
        """The server_stopped hook fires when the server is stopped."""
1187
        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.
1188
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1189
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1190
        self.setUpServer()
1191
        result = [([self.backing_transport.base], self.transport.base)]
1192
        # check the stopping message isn't emitted up front.
1193
        self.assertEqual([], self.hook_calls)
1194
        # nor after a single message
1195
        self.transport.has('.')
1196
        self.assertEqual([], self.hook_calls)
1197
        # clean up the server
1198
        self.tearDownServer()
1199
        # now it should have fired.
1200
        self.assertEqual(result, self.hook_calls)
1201
1202
    def test_server_stopped_hook_simple_file(self):
1203
        """The server_stopped hook fires when the server is stopped."""
1204
        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.
1205
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1206
            self.capture_server_call, None)
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1207
        self.setUpServer(backing_transport=get_transport("."))
1208
        result = [(
1209
            [self.backing_transport.base, self.backing_transport.external_url()]
1210
            , 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.
1211
        # check the stopping message isn't emitted up front.
1212
        self.assertEqual([], self.hook_calls)
1213
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1214
        self.transport.has('.')
1215
        self.assertEqual([], self.hook_calls)
1216
        # clean up the server
1217
        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.
1218
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1219
        self.assertEqual(result, self.hook_calls)
1220
1221
# TODO: test that when the server suffers an exception that it calls the
1222
# server-stopped hook.
1223
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1224
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1225
class SmartServerCommandTests(tests.TestCaseWithTransport):
1226
    """Tests that call directly into the command objects, bypassing the network
1227
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1228
1229
    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.
1230
    test_smart.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1231
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1232
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1233
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1234
        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)
1235
        response = cmd.execute()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1236
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1237
        self.assertEqual(None, response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
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_get_bundle(self):
1240
        from bzrlib.bundle import serializer
1241
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1242
        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
1243
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1244
        rev_id = wt.commit('add hello')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1245
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1246
        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)
1247
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1248
        bundle = serializer.read_bundle(StringIO(response.body))
1249
        self.assertEqual((), response.args)
1250
1251
1252
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1253
    """Test that call directly into the handler logic, bypassing the network."""
1254
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1255
    def setUp(self):
1256
        super(SmartServerRequestHandlerTests, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
1257
        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)
1258
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1259
    def build_handler(self, transport):
1260
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1261
        return _mod_request.SmartServerRequestHandler(
1262
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1263
1264
    def test_construct_request_handler(self):
1265
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1266
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1267
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1268
        self.assertFalse(handler.finished_reading)
1269
1270
    def test_hello(self):
1271
        handler = self.build_handler(None)
1272
        handler.dispatch_command('hello', ())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1273
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1274
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1275
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)
1276
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1277
        # VFS handler classes will raise an error from "execute" if
1278
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1279
        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)
1280
        # set environment variable after construction to make sure it's
1281
        # examined.
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1282
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1283
        # 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)
1284
        # afterwards.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1285
        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)
1286
        self.assertRaises(errors.DisabledMethod, handler.execute)
1287
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1288
    def test_readonly_exception_becomes_transport_not_possible(self):
1289
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1290
        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`.
1291
        # send a mkdir for foo, with no explicit mode - should fail.
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1292
        handler.dispatch_command('mkdir', ('foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1293
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1294
        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`.
1295
        # XXX: TODO: test that other TransportNotPossible errors are
1296
        # presented as TransportNotPossible - not possible to do that
1297
        # until I figure out how to trigger that relatively cleanly via
1298
        # the api. RBC 20060918
1299
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1300
    def test_hello_has_finished_body_on_dispatch(self):
1301
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1302
        handler = self.build_handler(None)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1303
        handler.dispatch_command('hello', ())
1304
        self.assertTrue(handler.finished_reading)
1305
        self.assertNotEqual(None, handler.response)
1306
1307
    def test_put_bytes_non_atomic(self):
1308
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1309
        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
1310
        handler.dispatch_command('put_non_atomic', ('a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1311
        self.assertFalse(handler.finished_reading)
1312
        handler.accept_body('1234')
1313
        self.assertFalse(handler.finished_reading)
1314
        handler.accept_body('5678')
1315
        handler.end_of_body()
1316
        self.assertTrue(handler.finished_reading)
1317
        self.assertEqual(('ok', ), handler.response.args)
1318
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1319
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1320
    def test_readv_accept_body(self):
1321
        """'readv' should set finished_reading after reading offsets."""
1322
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1323
        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
1324
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1325
        self.assertFalse(handler.finished_reading)
1326
        handler.accept_body('2,')
1327
        self.assertFalse(handler.finished_reading)
1328
        handler.accept_body('3')
1329
        handler.end_of_body()
1330
        self.assertTrue(handler.finished_reading)
1331
        self.assertEqual(('readv', ), handler.response.args)
1332
        # co - nte - nt of a-file is the file contents we are extracting from.
1333
        self.assertEqual('nte', handler.response.body)
1334
1335
    def test_readv_short_read_response_contents(self):
1336
        """'readv' when a short read occurs sets the response appropriately."""
1337
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1338
        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
1339
        handler.dispatch_command('readv', ('a-file', ))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1340
        # read beyond the end of the file.
1341
        handler.accept_body('100,1')
1342
        handler.end_of_body()
1343
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1344
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1345
            handler.response.args)
1346
        self.assertEqual(None, handler.response.body)
1347
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.
1348
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)
1349
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.
1350
1351
    def test_registration(self):
1352
        t = get_transport('bzr+ssh://example.com/path')
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1353
        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.
1354
        self.assertEqual('example.com', t._host)
1355
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1356
    def test_bzr_https(self):
1357
        # https://bugs.launchpad.net/bzr/+bug/128456
1358
        t = get_transport('bzr+https://example.com/path')
1359
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1360
        self.assertStartsWith(
1361
            t._http_transport.base,
1362
            'https://')
1363
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.
1364
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)
1365
class TestRemoteTransport(tests.TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1366
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1367
    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)
1368
        # 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.
1369
        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.
1370
        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.
1371
        client_medium = medium.SmartSimplePipesClientMedium(
1372
            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)
1373
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1374
            '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.
1375
        # 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).
1376
        client_medium._protocol_version = 1
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1377
1378
        # 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.
1379
        # method is called.  No data should have been sent, or read.
1380
        self.assertEqual(0, input.tell())
1381
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1382
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1383
        # 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.
1384
        # transport makes its own protocol instances, we check on the wire.
1385
        # XXX: TODO: give the transport a protocol factory, which can make
1386
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1387
        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.
1388
        # 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.
1389
        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.
1390
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1391
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1392
    def test__translate_error_readonly(self):
1393
        """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.
1394
        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)
1395
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1396
            'bzr://localhost/', medium=client_medium)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1397
        err = errors.ErrorFromSmartServer(("ReadOnlyError", ))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1398
        self.assertRaises(errors.TransportNotPossible,
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1399
            transport._translate_error, err)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1400
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1401
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1402
class TestSmartProtocol(tests.TestCase):
1403
    """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.
1404
1405
    Each test case gets a smart_server and smart_client created during setUp().
1406
1407
    It is planned that the client can be called with self.call_client() giving
1408
    it an expected server response, which will be fed into it when it tries to
1409
    read. Likewise, self.call_server will call a servers method with a canned
1410
    serialised client request. Output done by the client or server for these
1411
    calls will be captured to self.to_server and self.to_client. Each element
1412
    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.
1413
1414
    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.
1415
    """
1416
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1417
    request_encoder = None
1418
    response_decoder = None
1419
    server_protocol_class = None
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1420
    client_protocol_class = None
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1421
1422
    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.
1423
        """
1424
        :returns: a Request
1425
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1426
        # This is very similar to
1427
        # 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.
1428
        # XXX: make this use _SmartClient!
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1429
        if input_bytes is None:
1430
            input = StringIO()
1431
        else:
1432
            input = StringIO(input_bytes)
1433
        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.
1434
        client_medium = medium.SmartSimplePipesClientMedium(
1435
            input, output, 'base')
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1436
        request = client_medium.get_request()
1437
        if self.client_protocol_class is not None:
1438
            client_protocol = self.client_protocol_class(request)
1439
            return client_protocol, client_protocol, output
1440
        else:
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
1441
            self.assertNotEqual(None, self.request_encoder)
1442
            self.assertNotEqual(None, self.response_decoder)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1443
            requester = self.request_encoder(request)
1444
            response_handler = message.ConventionalResponseHandler()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1445
            response_protocol = self.response_decoder(
1446
                response_handler, expect_version_marker=True)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
1447
            response_handler.setProtoAndMediumRequest(
1448
                response_protocol, request)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1449
            return requester, response_handler, output
1450
1451
    def make_client_protocol(self, input_bytes=None):
1452
        result = self.make_client_protocol_and_output(input_bytes=input_bytes)
1453
        requester, response_handler, output = result
1454
        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.
1455
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1456
    def make_server_protocol(self):
1457
        out_stream = StringIO()
3245.4.34 by Andrew Bennetts
Remove another insignificant change vs. bzr.dev.
1458
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1459
        return smart_protocol, out_stream
1460
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.
1461
    def setUp(self):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1462
        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.
1463
        self.response_marker = getattr(
1464
            self.client_protocol_class, 'response_marker', None)
1465
        self.request_marker = getattr(
1466
            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.
1467
1468
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1469
        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.
1470
        """Check that smart (de)serialises offsets as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1471
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
        We check both serialisation and deserialisation at the same time
1473
        to ensure that the round tripping cannot skew: both directions should
1474
        be as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1475
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.
1476
        :param expected_offsets: a readv offset list.
1477
        :param expected_seralised: an expected serial form of the offsets.
1478
        """
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.
1479
        # XXX: '_deserialise_offsets' should be a method of the
1480
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1481
        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.
1482
        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.
1483
        self.assertEqual(expected_offsets, offsets)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1484
        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.
1485
        self.assertEqual(expected_serialised, serialised)
1486
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1487
    def build_protocol_waiting_for_body(self):
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1488
        smart_protocol, out_stream = self.make_server_protocol()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1489
        smart_protocol._has_dispatched = True
3245.1.14 by Andrew Bennetts
Merge from bzr.dev
1490
        smart_protocol.request = _mod_request.SmartServerRequestHandler(
1491
            None, _mod_request.request_handlers, '/')
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
1492
        class FakeCommand(_mod_request.SmartServerRequest):
1493
            def do_body(self_cmd, body_bytes):
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1494
                self.end_received = True
1495
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1496
                return _mod_request.SuccessfulSmartServerResponse(('ok', ))
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
1497
        smart_protocol.request._command = FakeCommand(None)
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1498
        # Call accept_bytes to make sure that internal state like _body_decoder
1499
        # is initialised.  This test should probably be given a clearer
1500
        # interface to work with that will not cause this inconsistency.
1501
        #   -- 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
1502
        smart_protocol.accept_bytes('')
1503
        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.
1504
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1505
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
1506
            input_tuples):
1507
        """Assert that each input_tuple serialises as expected_bytes, and the
1508
        bytes deserialise as expected_tuple.
1509
        """
1510
        # check the encoding of the server for all input_tuples matches
1511
        # expected bytes
1512
        for input_tuple in input_tuples:
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1513
            server_protocol, server_output = self.make_server_protocol()
2432.4.4 by Robert Collins
Merge hpss-protocol2.
1514
            server_protocol._send_response(
1515
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1516
            self.assertEqual(expected_bytes, server_output.getvalue())
1517
        # 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.
1518
        requester, response_handler = self.make_client_protocol(expected_bytes)
1519
        requester.call('foo')
1520
        self.assertEqual(expected_tuple, response_handler.read_response_tuple())
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1521
1522
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.
1523
class CommonSmartProtocolTestMixin(object):
1524
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1525
    def test_connection_closed_reporting(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1526
        requester, response_handler = self.make_client_protocol()
1527
        requester.call('hello')
3245.1.10 by Andrew Bennetts
Remove trailing whitespace.
1528
        ex = self.assertRaises(errors.ConnectionReset,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1529
            response_handler.read_response_tuple)
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1530
        self.assertEqual("Connection closed: "
4070.8.1 by Martin Pool
Remove 'try -Dhpss' from error messages
1531
            "please check connectivity and permissions ",
1532
            str(ex))
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1533
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1534
    def test_server_offset_serialisation(self):
1535
        """The Smart protocol serialises offsets as a comma and \n string.
1536
1537
        We check a number of boundary cases are as expected: empty, one offset,
1538
        one with the order of reads not increasing (an out of order read), and
1539
        one that should coalesce.
1540
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1541
        requester, response_handler = self.make_client_protocol()
1542
        self.assertOffsetSerialisation([], '', requester)
1543
        self.assertOffsetSerialisation([(1,2)], '1,2', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1544
        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.
1545
            requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1546
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1547
            '1,2\n3,4\n100,200', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1548
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.
1549
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.
1550
class TestVersionOneFeaturesInProtocolOne(
1551
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1552
    """Tests for version one smart protocol features as implemeted by version
1553
    one."""
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1554
1555
    client_protocol_class = protocol.SmartClientRequestProtocolOne
1556
    server_protocol_class = protocol.SmartServerRequestProtocolOne
1557
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1558
    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
1559
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1560
        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
1561
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1562
        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
1563
        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.
1564
1565
    def test_construct_version_one_client_protocol(self):
1566
        # we can construct a client protocol from a client medium request
1567
        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.
1568
        client_medium = medium.SmartSimplePipesClientMedium(
1569
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1570
        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
1571
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1572
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1573
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1574
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1575
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1576
            None, out_stream.write)
1577
        smart_protocol.accept_bytes('abc')
1578
        self.assertEqual('abc', smart_protocol.in_buffer)
1579
        smart_protocol.accept_bytes('\n')
1580
        self.assertEqual(
1581
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
1582
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1583
        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
1584
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
1585
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1586
    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.
1587
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1588
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1589
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1590
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1591
        protocol.accept_bytes('defgd')
1592
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1593
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1594
        self.assertTrue(self.end_received)
1595
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1596
    def test_accept_request_and_body_all_at_once(self):
2402.1.2 by Andrew Bennetts
Deal with review comments.
1597
        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.
1598
        mem_transport = memory.MemoryTransport()
1599
        mem_transport.put_bytes('foo', 'abcdefghij')
1600
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1601
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
1602
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1603
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1604
        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.
1605
        self.assertEqual('readv\n3\ndefdone\n', out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1606
        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
1607
        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.
1608
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1609
    def test_accept_excess_bytes_are_preserved(self):
1610
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1611
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1612
            None, out_stream.write)
1613
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1614
        self.assertEqual("ok\x012\n", out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1615
        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
1616
        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.
1617
1618
    def test_accept_excess_bytes_after_body(self):
1619
        protocol = self.build_protocol_waiting_for_body()
1620
        protocol.accept_bytes('7\nabcdefgdone\nX')
1621
        self.assertTrue(self.end_received)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1622
        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.
1623
        self.assertEqual("", protocol.in_buffer)
1624
        protocol.accept_bytes('Y')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1625
        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.
1626
        self.assertEqual("", protocol.in_buffer)
1627
1628
    def test_accept_excess_bytes_after_dispatch(self):
1629
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1630
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1631
            None, out_stream.write)
1632
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1633
        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
1634
        smart_protocol.accept_bytes('hel')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1635
        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
1636
        smart_protocol.accept_bytes('lo\n')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1637
        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
1638
        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.
1639
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1640
    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
1641
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1642
            None, lambda x: None)
1643
        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.
1644
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1645
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1646
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1647
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1648
    def test__send_response_errors_with_base_response(self):
1649
        """Ensure that only the Successful/Failed subclasses are used."""
1650
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1651
            None, lambda x: None)
1652
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1653
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1654
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1655
    def test_query_version(self):
1656
        """query_version on a SmartClientProtocolOne should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1657
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1658
        The protocol provides the query_version because the domain level clients
1659
        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.
1660
        """
1661
        # What we really want to test here is that SmartClientProtocolOne calls
1662
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1663
        # 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.
1664
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1665
        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.
1666
        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.
1667
        client_medium = medium.SmartSimplePipesClientMedium(
1668
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1669
        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
1670
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1671
        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.
1672
1673
    def test_client_call_empty_response(self):
1674
        # protocol.call() can get back an empty tuple as a response. This occurs
1675
        # when the parsed line is an empty line, and results in a tuple with
1676
        # one element - an empty string.
1677
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
1678
1679
    def test_client_call_three_element_response(self):
1680
        # protocol.call() can get back tuples of other lengths. A three element
1681
        # tuple should be unpacked as three strings.
1682
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
1683
            [('a', 'b', '34')])
1684
1685
    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.
1686
        # 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.
1687
        # wire.
1688
        expected_bytes = "foo\n7\nabcdefgdone\n"
1689
        input = StringIO("\n")
1690
        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.
1691
        client_medium = medium.SmartSimplePipesClientMedium(
1692
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1693
        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
1694
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1695
        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.
1696
        self.assertEqual(expected_bytes, output.getvalue())
1697
1698
    def test_client_call_with_body_readv_array(self):
1699
        # protocol.call_with_upload should encode the readv array and then
1700
        # length-prefix the bytes onto the wire.
1701
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
1702
        input = StringIO("\n")
1703
        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.
1704
        client_medium = medium.SmartSimplePipesClientMedium(
1705
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1706
        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
1707
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1708
        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.
1709
        self.assertEqual(expected_bytes, output.getvalue())
1710
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.
1711
    def _test_client_read_response_tuple_raises_UnknownSmartMethod(self,
1712
            server_bytes):
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1713
        input = StringIO(server_bytes)
1714
        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.
1715
        client_medium = medium.SmartSimplePipesClientMedium(
1716
            input, output, 'base')
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1717
        request = client_medium.get_request()
1718
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1719
        smart_protocol.call('foo')
1720
        self.assertRaises(
1721
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
1722
        # The request has been finished.  There is no body to read, and
1723
        # attempts to read one will fail.
1724
        self.assertRaises(
1725
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1726
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.
1727
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
1728
        """read_response_tuple raises UnknownSmartMethod if the response says
1729
        the server did not recognise the request.
1730
        """
1731
        server_bytes = (
1732
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
1733
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1734
            server_bytes)
1735
1736
    def test_client_read_response_tuple_raises_UnknownSmartMethod_0_11(self):
1737
        """read_response_tuple also raises UnknownSmartMethod if the response
1738
        from a bzr 0.11 says the server did not recognise the request.
1739
1740
        (bzr 0.11 sends a slightly different error message to later versions.)
1741
        """
1742
        server_bytes = (
1743
            "error\x01Generic bzr smart protocol error: bad request u'foo'\n")
1744
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1745
            server_bytes)
1746
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1747
    def test_client_read_body_bytes_all(self):
1748
        # read_body_bytes should decode the body bytes from the wire into
1749
        # a response.
1750
        expected_bytes = "1234567"
1751
        server_bytes = "ok\n7\n1234567done\n"
1752
        input = StringIO(server_bytes)
1753
        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.
1754
        client_medium = medium.SmartSimplePipesClientMedium(
1755
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1756
        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
1757
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1758
        smart_protocol.call('foo')
1759
        smart_protocol.read_response_tuple(True)
1760
        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.
1761
1762
    def test_client_read_body_bytes_incremental(self):
1763
        # test reading a few bytes at a time from the body
1764
        # 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.
1765
        # 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.
1766
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1767
        # that.
1768
        expected_bytes = "1234567"
1769
        server_bytes = "ok\n7\n1234567done\n"
1770
        input = StringIO(server_bytes)
1771
        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.
1772
        client_medium = medium.SmartSimplePipesClientMedium(
1773
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1774
        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
1775
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1776
        smart_protocol.call('foo')
1777
        smart_protocol.read_response_tuple(True)
1778
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1779
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1780
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1781
        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.
1782
1783
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1784
        # cancelling the expected body needs to finish the request, but not
1785
        # read any more bytes.
1786
        expected_bytes = "1234567"
1787
        server_bytes = "ok\n7\n1234567done\n"
1788
        input = StringIO(server_bytes)
1789
        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.
1790
        client_medium = medium.SmartSimplePipesClientMedium(
1791
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1792
        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
1793
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1794
        smart_protocol.call('foo')
1795
        smart_protocol.read_response_tuple(True)
1796
        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.
1797
        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
1798
        self.assertRaises(
1799
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1800
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
1801
    def test_client_read_body_bytes_interrupted_connection(self):
1802
        server_bytes = "ok\n999\nincomplete body"
1803
        input = StringIO(server_bytes)
1804
        output = StringIO()
1805
        client_medium = medium.SmartSimplePipesClientMedium(
1806
            input, output, 'base')
1807
        request = client_medium.get_request()
1808
        smart_protocol = self.client_protocol_class(request)
1809
        smart_protocol.call('foo')
1810
        smart_protocol.read_response_tuple(True)
1811
        self.assertRaises(
1812
            errors.ConnectionReset, smart_protocol.read_body_bytes)
1813
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1814
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.
1815
class TestVersionOneFeaturesInProtocolTwo(
1816
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1817
    """Tests for version one smart protocol features as implemeted by version
1818
    two.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1819
    """
1820
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1821
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
1822
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1823
1824
    def test_construct_version_two_server_protocol(self):
1825
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1826
        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.
1827
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1828
        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.
1829
        self.assertEqual(1, smart_protocol.next_read_size())
1830
1831
    def test_construct_version_two_client_protocol(self):
1832
        # we can construct a client protocol from a client medium request
1833
        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.
1834
        client_medium = medium.SmartSimplePipesClientMedium(
1835
            None, output, 'base')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1836
        request = client_medium.get_request()
1837
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1838
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1839
    def test_accept_bytes_of_bad_request_to_protocol(self):
1840
        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.
1841
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1842
        smart_protocol.accept_bytes('abc')
1843
        self.assertEqual('abc', smart_protocol.in_buffer)
1844
        smart_protocol.accept_bytes('\n')
1845
        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.
1846
            self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1847
            "failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
1848
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1849
        self.assertTrue(smart_protocol._has_dispatched)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1850
        self.assertEqual(0, smart_protocol.next_read_size())
1851
1852
    def test_accept_body_bytes_to_protocol(self):
1853
        protocol = self.build_protocol_waiting_for_body()
1854
        self.assertEqual(6, protocol.next_read_size())
1855
        protocol.accept_bytes('7\nabc')
1856
        self.assertEqual(9, protocol.next_read_size())
1857
        protocol.accept_bytes('defgd')
1858
        protocol.accept_bytes('one\n')
1859
        self.assertEqual(0, protocol.next_read_size())
1860
        self.assertTrue(self.end_received)
1861
1862
    def test_accept_request_and_body_all_at_once(self):
1863
        self._captureVar('BZR_NO_SMART_VFS', None)
1864
        mem_transport = memory.MemoryTransport()
1865
        mem_transport.put_bytes('foo', 'abcdefghij')
1866
        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.
1867
        smart_protocol = self.server_protocol_class(
1868
            mem_transport, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1869
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1870
        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.
1871
        self.assertEqual(self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1872
                         'success\nreadv\n3\ndefdone\n',
1873
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1874
        self.assertEqual('', smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1875
        self.assertEqual('', smart_protocol.in_buffer)
1876
1877
    def test_accept_excess_bytes_are_preserved(self):
1878
        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.
1879
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1880
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1881
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1882
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1883
        self.assertEqual("hello\n", smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1884
        self.assertEqual("", smart_protocol.in_buffer)
1885
1886
    def test_accept_excess_bytes_after_body(self):
1887
        # The excess bytes look like the start of another request.
1888
        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.
1889
        server_protocol.accept_bytes('7\nabcdefgdone\n' + self.response_marker)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1890
        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.
1891
        self.assertEqual(self.response_marker,
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1892
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1893
        self.assertEqual("", server_protocol.in_buffer)
1894
        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.
1895
        self.assertEqual(self.response_marker + "Y",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1896
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1897
        self.assertEqual("", server_protocol.in_buffer)
1898
1899
    def test_accept_excess_bytes_after_dispatch(self):
1900
        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.
1901
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1902
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1903
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1904
                         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.
1905
        smart_protocol.accept_bytes(self.request_marker + 'hel')
1906
        self.assertEqual(self.request_marker + "hel",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1907
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1908
        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.
1909
        self.assertEqual(self.request_marker + "hello\n",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1910
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1911
        self.assertEqual("", smart_protocol.in_buffer)
1912
1913
    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.
1914
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1915
        self.assertEqual(1, smart_protocol.next_read_size())
1916
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1917
            _mod_request.SuccessfulSmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1918
        self.assertEqual(0, smart_protocol.next_read_size())
1919
1920
    def test__send_response_errors_with_base_response(self):
1921
        """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.
1922
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1923
        self.assertRaises(AttributeError, smart_protocol._send_response,
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1924
            _mod_request.SmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1925
1926
    def test_query_version(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
1927
        """query_version on a SmartClientProtocolTwo should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1928
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1929
        The protocol provides the query_version because the domain level clients
1930
        may all need to be able to probe for capabilities.
1931
        """
1932
        # What we really want to test here is that SmartClientProtocolTwo calls
1933
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
1934
        # response of tuple-encoded (ok, 1).  Also, seperately we should test
1935
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1936
        input = StringIO(self.response_marker + 'success\nok\x012\n')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1937
        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.
1938
        client_medium = medium.SmartSimplePipesClientMedium(
1939
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1940
        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.
1941
        smart_protocol = self.client_protocol_class(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1942
        self.assertEqual(2, smart_protocol.query_version())
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1943
1944
    def test_client_call_empty_response(self):
1945
        # protocol.call() can get back an empty tuple as a response. This occurs
1946
        # when the parsed line is an empty line, and results in a tuple with
1947
        # one element - an empty string.
1948
        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.
1949
            self.response_marker + 'success\n\n', ('', ), [(), ('', )])
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1950
1951
    def test_client_call_three_element_response(self):
1952
        # protocol.call() can get back tuples of other lengths. A three element
1953
        # tuple should be unpacked as three strings.
1954
        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.
1955
            self.response_marker + 'success\na\x01b\x0134\n',
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1956
            ('a', 'b', '34'),
1957
            [('a', 'b', '34')])
1958
1959
    def test_client_call_with_body_bytes_uploads(self):
1960
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
1961
        # 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.
1962
        expected_bytes = self.request_marker + "foo\n7\nabcdefgdone\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1963
        input = StringIO("\n")
1964
        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.
1965
        client_medium = medium.SmartSimplePipesClientMedium(
1966
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1967
        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.
1968
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1969
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1970
        self.assertEqual(expected_bytes, output.getvalue())
1971
1972
    def test_client_call_with_body_readv_array(self):
1973
        # protocol.call_with_upload should encode the readv array and then
1974
        # 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.
1975
        expected_bytes = self.request_marker + "foo\n7\n1,2\n5,6done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1976
        input = StringIO("\n")
1977
        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.
1978
        client_medium = medium.SmartSimplePipesClientMedium(
1979
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1980
        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.
1981
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1982
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1983
        self.assertEqual(expected_bytes, output.getvalue())
1984
1985
    def test_client_read_body_bytes_all(self):
1986
        # read_body_bytes should decode the body bytes from the wire into
1987
        # a response.
1988
        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.
1989
        server_bytes = (self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1990
                        "success\nok\n7\n1234567done\n")
1991
        input = StringIO(server_bytes)
1992
        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.
1993
        client_medium = medium.SmartSimplePipesClientMedium(
1994
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1995
        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.
1996
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1997
        smart_protocol.call('foo')
1998
        smart_protocol.read_response_tuple(True)
1999
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
2000
2001
    def test_client_read_body_bytes_incremental(self):
2002
        # test reading a few bytes at a time from the body
2003
        # XXX: possibly we should test dribbling the bytes into the stringio
2004
        # to make the state machine work harder: however, as we use the
2005
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
2006
        # that.
2007
        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.
2008
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2009
        input = StringIO(server_bytes)
2010
        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.
2011
        client_medium = medium.SmartSimplePipesClientMedium(
2012
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2013
        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.
2014
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2015
        smart_protocol.call('foo')
2016
        smart_protocol.read_response_tuple(True)
2017
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2018
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2019
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2020
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2021
2022
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2023
        # cancelling the expected body needs to finish the request, but not
2024
        # 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.
2025
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2026
        input = StringIO(server_bytes)
2027
        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.
2028
        client_medium = medium.SmartSimplePipesClientMedium(
2029
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2030
        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.
2031
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2032
        smart_protocol.call('foo')
2033
        smart_protocol.read_response_tuple(True)
2034
        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.
2035
        self.assertEqual(len(self.response_marker + 'success\nok\n'),
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2036
                         input.tell())
2037
        self.assertRaises(
2038
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2039
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2040
    def test_client_read_body_bytes_interrupted_connection(self):
2041
        server_bytes = (self.response_marker +
2042
                        "success\nok\n999\nincomplete body")
2043
        input = StringIO(server_bytes)
2044
        output = StringIO()
2045
        client_medium = medium.SmartSimplePipesClientMedium(
2046
            input, output, 'base')
2047
        request = client_medium.get_request()
2048
        smart_protocol = self.client_protocol_class(request)
2049
        smart_protocol.call('foo')
2050
        smart_protocol.read_response_tuple(True)
2051
        self.assertRaises(
2052
            errors.ConnectionReset, smart_protocol.read_body_bytes)
2053
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2054
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.
2055
class TestSmartProtocolTwoSpecificsMixin(object):
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2056
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2057
    def assertBodyStreamSerialisation(self, expected_serialisation,
2058
                                      body_stream):
2059
        """Assert that body_stream is serialised as expected_serialisation."""
2060
        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.
2061
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
2062
        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.
2063
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.
2064
    def assertBodyStreamRoundTrips(self, body_stream):
2065
        """Assert that body_stream is the same after being serialised and
2066
        deserialised.
2067
        """
2068
        out_stream = StringIO()
2069
        protocol._send_stream(body_stream, out_stream.write)
2070
        decoder = protocol.ChunkedBodyDecoder()
2071
        decoder.accept_bytes(out_stream.getvalue())
2072
        decoded_stream = list(iter(decoder.read_next_chunk, None))
2073
        self.assertEqual(body_stream, decoded_stream)
2074
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2075
    def test_body_stream_serialisation_empty(self):
2076
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2077
        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.
2078
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2079
2080
    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.
2081
        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.
2082
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2083
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
2084
            '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.
2085
            stream)
2086
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2087
2088
    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.
2089
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2090
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2091
        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.
2092
        """
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.
2093
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2094
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2095
            '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.
2096
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2097
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2098
    def test_body_stream_error_serialistion(self):
2099
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2100
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2101
                      ('FailureName', 'failure arg'))]
2102
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2103
            '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.
2104
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
2105
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2106
        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.
2107
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2108
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2109
    def test__send_response_includes_failure_marker(self):
2110
        """FailedSmartServerResponse have 'failed\n' after the version."""
2111
        out_stream = StringIO()
2112
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2113
            None, out_stream.write)
2114
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2115
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2116
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
2117
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2118
2119
    def test__send_response_includes_success_marker(self):
2120
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
2121
        out_stream = StringIO()
2122
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2123
            None, out_stream.write)
2124
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2125
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2126
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
2127
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2128
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2129
    def test__send_response_with_body_stream_sets_finished_reading(self):
2130
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2131
            None, lambda x: None)
2132
        self.assertEqual(1, smart_protocol.next_read_size())
2133
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2134
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2135
        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.
2136
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2137
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2138
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2139
        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.
2140
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2141
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2142
                        "success\nok\n" + body_header + two_body_chunks +
2143
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2144
        input = StringIO(server_bytes)
2145
        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.
2146
        client_medium = medium.SmartSimplePipesClientMedium(
2147
            input, output, 'base')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2148
        request = client_medium.get_request()
2149
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2150
        smart_protocol.call('foo')
2151
        smart_protocol.read_response_tuple(True)
2152
        stream = smart_protocol.read_streamed_body()
2153
        self.assertEqual(['1234', '567'], list(stream))
2154
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2155
    def test_read_streamed_body_error(self):
2156
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2157
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2158
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2159
        err_signal = 'ERR\n'
2160
        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.
2161
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2162
        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.
2163
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2164
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2165
        input = StringIO(server_bytes)
2166
        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.
2167
        client_medium = medium.SmartSimplePipesClientMedium(
2168
            input, output, 'base')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2169
        smart_request = client_medium.get_request()
2170
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2171
        smart_protocol.call('foo')
2172
        smart_protocol.read_response_tuple(True)
2173
        expected_chunks = [
2174
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2175
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2176
        stream = smart_protocol.read_streamed_body()
2177
        self.assertEqual(expected_chunks, list(stream))
2178
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2179
    def test_streamed_body_bytes_interrupted_connection(self):
2180
        body_header = 'chunked\n'
2181
        incomplete_body_chunk = "9999\nincomplete chunk"
2182
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2183
                        "success\nok\n" + body_header + incomplete_body_chunk)
2184
        input = StringIO(server_bytes)
2185
        output = StringIO()
2186
        client_medium = medium.SmartSimplePipesClientMedium(
2187
            input, output, 'base')
2188
        request = client_medium.get_request()
2189
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2190
        smart_protocol.call('foo')
2191
        smart_protocol.read_response_tuple(True)
2192
        stream = smart_protocol.read_streamed_body()
2193
        self.assertRaises(errors.ConnectionReset, stream.next)
2194
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2195
    def test_client_read_response_tuple_sets_response_status(self):
2196
        server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
2197
        input = StringIO(server_bytes)
2198
        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.
2199
        client_medium = medium.SmartSimplePipesClientMedium(
2200
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2201
        request = client_medium.get_request()
2202
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2203
        smart_protocol.call('foo')
2204
        smart_protocol.read_response_tuple(False)
2205
        self.assertEqual(True, smart_protocol.response_status)
2206
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2207
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2208
        """read_response_tuple raises UnknownSmartMethod if the response says
2209
        the server did not recognise the request.
2210
        """
2211
        server_bytes = (
2212
            protocol.RESPONSE_VERSION_TWO +
2213
            "failed\n" +
2214
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2215
        input = StringIO(server_bytes)
2216
        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.
2217
        client_medium = medium.SmartSimplePipesClientMedium(
2218
            input, output, 'base')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2219
        request = client_medium.get_request()
2220
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2221
        smart_protocol.call('foo')
2222
        self.assertRaises(
2223
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2224
        # The request has been finished.  There is no body to read, and
2225
        # attempts to read one will fail.
2226
        self.assertRaises(
2227
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2228
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2229
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.
2230
class TestSmartProtocolTwoSpecifics(
2231
        TestSmartProtocol, TestSmartProtocolTwoSpecificsMixin):
2232
    """Tests for aspects of smart protocol version two that are unique to
2233
    version two.
2234
2235
    Thus tests involving body streams and success/failure markers belong here.
2236
    """
2237
2238
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
2239
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2240
2241
2242
class TestVersionOneFeaturesInProtocolThree(
2243
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2244
    """Tests for version one smart protocol features as implemented by version
2245
    three.
2246
    """
2247
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2248
    request_encoder = protocol.ProtocolThreeRequester
2249
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2250
    # build_server_protocol_three is a function, so we can't set it as a class
2251
    # 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.
2252
    # method.  So we make server_protocol_class be a static method, rather than
2253
    # simply doing:
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2254
    # "server_protocol_class = protocol.build_server_protocol_three".
3245.4.10 by Andrew Bennetts
Use a less ugly hack for TestVersionOneFeaturesInProtocolThree.server_protocol_class.
2255
    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.
2256
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2257
    def setUp(self):
2258
        super(TestVersionOneFeaturesInProtocolThree, self).setUp()
2259
        self.response_marker = protocol.MESSAGE_VERSION_THREE
2260
        self.request_marker = protocol.MESSAGE_VERSION_THREE
2261
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.
2262
    def test_construct_version_three_server_protocol(self):
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2263
        smart_protocol = protocol.ProtocolThreeDecoder(None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2264
        self.assertEqual('', smart_protocol.unused_data)
3649.5.5 by John Arbash Meinel
Fix the test suite.
2265
        self.assertEqual([], smart_protocol._in_buffer_list)
2266
        self.assertEqual(0, smart_protocol._in_buffer_len)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2267
        self.assertFalse(smart_protocol._has_dispatched)
3195.3.19 by Andrew Bennetts
Remove a stray pdb, fix a test.
2268
        # The protocol starts by expecting four bytes, a length prefix for the
2269
        # headers.
2270
        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.
2271
2272
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2273
class LoggingMessageHandler(object):
2274
2275
    def __init__(self):
2276
        self.event_log = []
2277
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2278
    def _log(self, *args):
2279
        self.event_log.append(args)
2280
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2281
    def headers_received(self, headers):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2282
        self._log('headers', headers)
2283
2284
    def protocol_error(self, exception):
2285
        self._log('protocol_error', exception)
2286
2287
    def byte_part_received(self, byte):
2288
        self._log('byte', byte)
2289
2290
    def bytes_part_received(self, bytes):
2291
        self._log('bytes', bytes)
2292
2293
    def structure_part_received(self, structure):
2294
        self._log('structure', structure)
2295
2296
    def end_received(self):
2297
        self._log('end')
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2298
2299
2300
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.
2301
    """Tests for v3 of the server-side protocol."""
2302
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2303
    request_encoder = protocol.ProtocolThreeRequester
2304
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2305
    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.
2306
2307
    def test_trivial_request(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2308
        """Smoke test for the simplest possible v3 request: empty headers, no
2309
        message parts.
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2310
        """
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.
2311
        output = StringIO()
2312
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2313
        end = 'e'
2314
        request_bytes = headers + end
2315
        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.
2316
        smart_protocol.accept_bytes(request_bytes)
2317
        self.assertEqual(0, smart_protocol.next_read_size())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2318
        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.
2319
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2320
    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.
2321
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2322
        message_handler = LoggingMessageHandler()
2323
        smart_protocol = self.server_protocol_class(message_handler)
2324
        smart_protocol.accept_bytes(headers)
2325
        # Clear the event log
2326
        del message_handler.event_log[:]
2327
        return smart_protocol, message_handler.event_log
2328
2329
    def test_decode_one_byte(self):
2330
        """The protocol can decode a 'one byte' message part."""
2331
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2332
        smart_protocol.accept_bytes('ox')
2333
        self.assertEqual([('byte', 'x')], event_log)
2334
2335
    def test_decode_bytes(self):
2336
        """The protocol can decode a 'bytes' message part."""
2337
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2338
        smart_protocol.accept_bytes(
2339
            'b' # message part kind
2340
            '\0\0\0\x07' # length prefix
2341
            'payload' # payload
2342
            )
2343
        self.assertEqual([('bytes', 'payload')], event_log)
2344
2345
    def test_decode_structure(self):
2346
        """The protocol can decode a 'structure' message part."""
2347
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2348
        smart_protocol.accept_bytes(
2349
            's' # message part kind
2350
            '\0\0\0\x07' # length prefix
2351
            'l3:ARGe' # ['ARG']
2352
            )
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
2353
        self.assertEqual([('structure', ('ARG',))], event_log)
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2354
2355
    def test_decode_multiple_bytes(self):
2356
        """The protocol can decode a multiple 'bytes' message parts."""
2357
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2358
        smart_protocol.accept_bytes(
2359
            'b' # message part kind
2360
            '\0\0\0\x05' # length prefix
2361
            'first' # payload
2362
            'b' # message part kind
2363
            '\0\0\0\x06'
2364
            'second'
2365
            )
2366
        self.assertEqual(
2367
            [('bytes', 'first'), ('bytes', 'second')], event_log)
2368
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.
2369
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2370
class TestConventionalResponseHandlerBodyStream(tests.TestCase):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2371
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2372
    def make_response_handler(self, response_bytes):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2373
        from bzrlib.smart.message import ConventionalResponseHandler
2374
        response_handler = ConventionalResponseHandler()
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2375
        protocol_decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2376
        # put decoder in desired state (waiting for message parts)
2377
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2378
        output = StringIO()
2379
        client_medium = medium.SmartSimplePipesClientMedium(
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2380
            StringIO(response_bytes), output, 'base')
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2381
        medium_request = client_medium.get_request()
2382
        medium_request.finished_writing()
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2383
        response_handler.setProtoAndMediumRequest(
2384
            protocol_decoder, medium_request)
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2385
        return response_handler
2386
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2387
    def test_interrupted_by_error(self):
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2388
        response_handler = self.make_response_handler(interrupted_body_stream)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2389
        stream = response_handler.read_streamed_body()
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2390
        self.assertEqual('aaa', stream.next())
2391
        self.assertEqual('bbb', stream.next())
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2392
        exc = self.assertRaises(errors.ErrorFromSmartServer, stream.next)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2393
        self.assertEqual(('error', 'Boom!'), exc.error_tuple)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2394
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2395
    def test_interrupted_by_connection_lost(self):
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2396
        interrupted_body_stream = (
2397
            'oS' # successful response
2398
            's\0\0\0\x02le' # empty args
2399
            'b\0\0\xff\xffincomplete chunk')
2400
        response_handler = self.make_response_handler(interrupted_body_stream)
2401
        stream = response_handler.read_streamed_body()
2402
        self.assertRaises(errors.ConnectionReset, stream.next)
2403
2404
    def test_read_body_bytes_interrupted_by_connection_lost(self):
2405
        interrupted_body_stream = (
2406
            'oS' # successful response
2407
            's\0\0\0\x02le' # empty args
2408
            'b\0\0\xff\xffincomplete chunk')
2409
        response_handler = self.make_response_handler(interrupted_body_stream)
2410
        self.assertRaises(
2411
            errors.ConnectionReset, response_handler.read_body_bytes)
2412
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2413
    def test_multiple_bytes_parts(self):
2414
        multiple_bytes_parts = (
2415
            'oS' # successful response
2416
            's\0\0\0\x02le' # empty args
2417
            'b\0\0\0\x0bSome bytes\n' # some bytes
2418
            'b\0\0\0\x0aMore bytes' # more bytes
2419
            'e' # message end
2420
            )
2421
        response_handler = self.make_response_handler(multiple_bytes_parts)
2422
        self.assertEqual(
2423
            'Some bytes\nMore bytes', response_handler.read_body_bytes())
2424
        response_handler = self.make_response_handler(multiple_bytes_parts)
2425
        self.assertEqual(
2426
            ['Some bytes\n', 'More bytes'],
2427
            list(response_handler.read_streamed_body()))
2428
2429
3923.5.6 by Andrew Bennetts
Fix a style nit.
2430
class FakeResponder(object):
2431
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2432
    response_sent = False
3923.5.6 by Andrew Bennetts
Fix a style nit.
2433
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2434
    def send_error(self, exc):
2435
        raise exc
3923.5.6 by Andrew Bennetts
Fix a style nit.
2436
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2437
    def send_response(self, response):
2438
        pass
2439
2440
2441
class TestConventionalRequestHandlerBodyStream(tests.TestCase):
2442
    """Tests for ConventionalRequestHandler's handling of request bodies."""
2443
2444
    def make_request_handler(self, request_bytes):
2445
        """Make a ConventionalRequestHandler for the given bytes using test
2446
        doubles for the request_handler and the responder.
2447
        """
2448
        from bzrlib.smart.message import ConventionalRequestHandler
2449
        request_handler = InstrumentedRequestHandler()
2450
        request_handler.response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
3923.5.6 by Andrew Bennetts
Fix a style nit.
2451
        responder = FakeResponder()
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2452
        message_handler = ConventionalRequestHandler(request_handler, responder)
2453
        protocol_decoder = protocol.ProtocolThreeDecoder(message_handler)
2454
        # put decoder in desired state (waiting for message parts)
2455
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2456
        protocol_decoder.accept_bytes(request_bytes)
2457
        return request_handler
2458
2459
    def test_multiple_bytes_parts(self):
2460
        """Each bytes part triggers a call to the request_handler's
2461
        accept_body method.
2462
        """
2463
        multiple_bytes_parts = (
2464
            's\0\0\0\x07l3:fooe' # args
2465
            'b\0\0\0\x0bSome bytes\n' # some bytes
2466
            'b\0\0\0\x0aMore bytes' # more bytes
2467
            'e' # message end
2468
            )
2469
        request_handler = self.make_request_handler(multiple_bytes_parts)
2470
        accept_body_calls = [
2471
            call_info[1] for call_info in request_handler.calls
2472
            if call_info[0] == 'accept_body']
2473
        self.assertEqual(
2474
            ['Some bytes\n', 'More bytes'], accept_body_calls)
2475
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
2476
    def test_error_flag_after_body(self):
2477
        body_then_error = (
2478
            's\0\0\0\x07l3:fooe' # request args
2479
            'b\0\0\0\x0bSome bytes\n' # some bytes
2480
            'b\0\0\0\x0aMore bytes' # more bytes
2481
            'oE' # error flag
2482
            's\0\0\0\x07l3:bare' # error args
2483
            'e' # message end
2484
            )
2485
        request_handler = self.make_request_handler(body_then_error)
2486
        self.assertEqual(
2487
            [('post_body_error_received', ('bar',)), ('end_received',)],
2488
            request_handler.calls[-2:])
2489
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2490
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.
2491
class TestMessageHandlerErrors(tests.TestCase):
2492
    """Tests for v3 that unrecognised (but well-formed) requests/responses are
2493
    still fully read off the wire, so that subsequent requests/responses on the
2494
    same medium can be decoded.
2495
    """
2496
2497
    def test_non_conventional_request(self):
2498
        """ConventionalRequestHandler (the default message handler on the
2499
        server side) will reject an unconventional message, but still consume
2500
        all the bytes of that message and signal when it has done so.
2501
2502
        This is what allows a server to continue to accept requests after the
2503
        client sends a completely unrecognised request.
2504
        """
2505
        # Define an invalid request (but one that is a well-formed message).
2506
        # This particular invalid request not only lacks the mandatory
2507
        # verb+args tuple, it has a single-byte part, which is forbidden.  In
2508
        # fact it has that part twice, to trigger multiple errors.
2509
        invalid_request = (
2510
            protocol.MESSAGE_VERSION_THREE +  # protocol version marker
2511
            '\0\0\0\x02de' + # empty headers
2512
            'oX' + # a single byte part: 'X'.  ConventionalRequestHandler will
2513
                   # error at this part.
2514
            'oX' + # and again.
2515
            'e' # end of message
2516
            )
2517
2518
        to_server = StringIO(invalid_request)
2519
        from_server = StringIO()
2520
        transport = memory.MemoryTransport('memory:///')
2521
        server = medium.SmartServerPipeStreamMedium(
2522
            to_server, from_server, transport)
2523
        proto = server._build_protocol()
2524
        message_handler = proto.message_handler
2525
        server._serve_one_request(proto)
2526
        # All the bytes have been read from the medium...
2527
        self.assertEqual('', to_server.read())
2528
        # ...and the protocol decoder has consumed all the bytes, and has
2529
        # finished reading.
2530
        self.assertEqual('', proto.unused_data)
2531
        self.assertEqual(0, proto.next_read_size())
2532
2533
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.
2534
class InstrumentedRequestHandler(object):
2535
    """Test Double of SmartServerRequestHandler."""
2536
2537
    def __init__(self):
2538
        self.calls = []
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2539
        self.finished_reading = False
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.
2540
2541
    def no_body_received(self):
2542
        self.calls.append(('no_body_received',))
2543
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).
2544
    def end_received(self):
2545
        self.calls.append(('end_received',))
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2546
        self.finished_reading = True
2547
2548
    def dispatch_command(self, cmd, args):
2549
        self.calls.append(('dispatch_command', cmd, args))
2550
2551
    def accept_body(self, bytes):
2552
        self.calls.append(('accept_body', bytes))
2553
2554
    def end_of_body(self):
2555
        self.calls.append(('end_of_body',))
2556
        self.finished_reading = True
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).
2557
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
2558
    def post_body_error_received(self, error_args):
2559
        self.calls.append(('post_body_error_received', error_args))
2560
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.
2561
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2562
class StubRequest(object):
2563
2564
    def finished_reading(self):
2565
        pass
2566
2567
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2568
class TestClientDecodingProtocolThree(TestSmartProtocol):
2569
    """Tests for v3 of the client-side protocol decoding."""
2570
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2571
    def make_logging_response_decoder(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2572
        """Make v3 response decoder using a test response handler."""
2573
        response_handler = LoggingMessageHandler()
2574
        decoder = protocol.ProtocolThreeDecoder(response_handler)
2575
        return decoder, response_handler
2576
2577
    def make_conventional_response_decoder(self):
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2578
        """Make v3 response decoder using a conventional response handler."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2579
        response_handler = message.ConventionalResponseHandler()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2580
        decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2581
        response_handler.setProtoAndMediumRequest(decoder, StubRequest())
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2582
        return decoder, response_handler
2583
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2584
    def test_trivial_response_decoding(self):
2585
        """Smoke test for the simplest possible v3 response: empty headers,
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2586
        status byte, empty args, no body.
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2587
        """
2588
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2589
        response_status = 'oS' # success
2590
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2591
        end = 'e' # end marker
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2592
        message_bytes = headers + response_status + args + end
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2593
        decoder, response_handler = self.make_logging_response_decoder()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2594
        decoder.accept_bytes(message_bytes)
2595
        # The protocol decoder has finished, and consumed all bytes
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2596
        self.assertEqual(0, decoder.next_read_size())
2597
        self.assertEqual('', decoder.unused_data)
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2598
        # The message handler has been invoked with all the parts of the
2599
        # trivial response: empty headers, status byte, no args, end.
2600
        self.assertEqual(
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
2601
            [('headers', {}), ('byte', 'S'), ('structure', ()), ('end',)],
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2602
            response_handler.event_log)
3195.3.5 by Andrew Bennetts
Start writing the client-side protocol logic for HPSS v3.
2603
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2604
    def test_incomplete_message(self):
2605
        """A decoder will keep signalling that it needs more bytes via
2606
        next_read_size() != 0 until it has seen a complete message, regardless
2607
        which state it is in.
2608
        """
2609
        # Define a simple response that uses all possible message parts.
2610
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2611
        response_status = 'oS' # success
2612
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2613
        body = 'b\0\0\0\x04BODY' # a body: 'BODY'
2614
        end = 'e' # end marker
2615
        simple_response = headers + response_status + args + body + end
2616
        # Feed the request to the decoder one byte at a time.
2617
        decoder, response_handler = self.make_logging_response_decoder()
2618
        for byte in simple_response:
2619
            self.assertNotEqual(0, decoder.next_read_size())
2620
            decoder.accept_bytes(byte)
2621
        # Now the response is complete
2622
        self.assertEqual(0, decoder.next_read_size())
2623
2624
    def test_read_response_tuple_raises_UnknownSmartMethod(self):
2625
        """read_response_tuple raises UnknownSmartMethod if the server replied
2626
        with 'UnknownMethod'.
2627
        """
3245.4.35 by Andrew Bennetts
Remove some commented out cruft, test (and fix) handling of an 'UnknownMethod' response.
2628
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2629
        response_status = 'oE' # error flag
2630
        # args: ('UnknownMethod', 'method-name')
2631
        args = 's\0\0\0\x20l13:UnknownMethod11:method-namee'
2632
        end = 'e' # end marker
2633
        message_bytes = headers + response_status + args + end
2634
        decoder, response_handler = self.make_conventional_response_decoder()
2635
        decoder.accept_bytes(message_bytes)
2636
        error = self.assertRaises(
2637
            errors.UnknownSmartMethod, response_handler.read_response_tuple)
2638
        self.assertEqual('method-name', error.verb)
2639
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2640
    def test_read_response_tuple_error(self):
2641
        """If the response has an error, it is raised as an exception."""
2642
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2643
        response_status = 'oE' # error
2644
        args = 's\0\0\0\x1al9:first arg10:second arge' # two args
2645
        end = 'e' # end marker
2646
        message_bytes = headers + response_status + args + end
2647
        decoder, response_handler = self.make_conventional_response_decoder()
2648
        decoder.accept_bytes(message_bytes)
2649
        error = self.assertRaises(
2650
            errors.ErrorFromSmartServer, response_handler.read_response_tuple)
2651
        self.assertEqual(('first arg', 'second arg'), error.error_tuple)
2652
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.
2653
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2654
class TestClientEncodingProtocolThree(TestSmartProtocol):
2655
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2656
    request_encoder = protocol.ProtocolThreeRequester
2657
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2658
    server_protocol_class = protocol.ProtocolThreeDecoder
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2659
2660
    def make_client_encoder_and_output(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2661
        result = self.make_client_protocol_and_output()
2662
        requester, response_handler, output = result
2663
        return requester, output
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2664
2665
    def test_call_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2666
        """A smoke test for ProtocolThreeRequester.call.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2667
2668
        This test checks that a particular simple invocation of call emits the
2669
        correct bytes for that invocation.
2670
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2671
        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.
2672
        requester.set_headers({'header name': 'header value'})
2673
        requester.call('one arg')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2674
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2675
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2676
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2677
            's\x00\x00\x00\x0bl7:one arge' # args
2678
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2679
            output.getvalue())
2680
2681
    def test_call_with_body_bytes_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2682
        """A smoke test for ProtocolThreeRequester.call_with_body_bytes.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2683
2684
        This test checks that a particular simple invocation of
2685
        call_with_body_bytes emits the correct bytes for that invocation.
2686
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2687
        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.
2688
        requester.set_headers({'header name': 'header value'})
2689
        requester.call_with_body_bytes(('one arg',), 'body bytes')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2690
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2691
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2692
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2693
            's\x00\x00\x00\x0bl7:one arge' # args
2694
            'b' # there is a prefixed body
2695
            '\x00\x00\x00\nbody bytes' # the prefixed body
2696
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2697
            output.getvalue())
2698
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.
2699
    def test_call_writes_just_once(self):
2700
        """A bodyless request is written to the medium all at once."""
2701
        medium_request = StubMediumRequest()
2702
        encoder = protocol.ProtocolThreeRequester(medium_request)
2703
        encoder.call('arg1', 'arg2', 'arg3')
2704
        self.assertEqual(
2705
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2706
2707
    def test_call_with_body_bytes_writes_just_once(self):
2708
        """A request with body bytes is written to the medium all at once."""
2709
        medium_request = StubMediumRequest()
2710
        encoder = protocol.ProtocolThreeRequester(medium_request)
2711
        encoder.call_with_body_bytes(('arg', 'arg'), 'body bytes')
2712
        self.assertEqual(
2713
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2714
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2715
    def test_call_with_body_stream_smoke_test(self):
2716
        """A smoke test for ProtocolThreeRequester.call_with_body_stream.
2717
2718
        This test checks that a particular simple invocation of
2719
        call_with_body_stream emits the correct bytes for that invocation.
2720
        """
2721
        requester, output = self.make_client_encoder_and_output()
2722
        requester.set_headers({'header name': 'header value'})
2723
        stream = ['chunk 1', 'chunk two']
2724
        requester.call_with_body_stream(('one arg',), stream)
2725
        self.assertEquals(
2726
            'bzr message 3 (bzr 1.6)\n' # protocol version
2727
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
2728
            's\x00\x00\x00\x0bl7:one arge' # args
2729
            'b\x00\x00\x00\x07chunk 1' # a prefixed body chunk
2730
            'b\x00\x00\x00\x09chunk two' # a prefixed body chunk
2731
            'e', # end
2732
            output.getvalue())
2733
2734
    def test_call_with_body_stream_empty_stream(self):
2735
        """call_with_body_stream with an empty stream."""
2736
        requester, output = self.make_client_encoder_and_output()
2737
        requester.set_headers({})
2738
        stream = []
2739
        requester.call_with_body_stream(('one arg',), stream)
2740
        self.assertEquals(
2741
            'bzr message 3 (bzr 1.6)\n' # protocol version
2742
            '\x00\x00\x00\x02de' # headers
2743
            's\x00\x00\x00\x0bl7:one arge' # args
2744
            # no body chunks
2745
            'e', # end
2746
            output.getvalue())
2747
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2748
    def test_call_with_body_stream_error(self):
2749
        """call_with_body_stream will abort the streamed body with an
2750
        error if the stream raises an error during iteration.
4032.1.1 by John Arbash Meinel
Merge the removal of all trailing whitespace, and resolve conflicts.
2751
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2752
        The resulting request will still be a complete message.
2753
        """
2754
        requester, output = self.make_client_encoder_and_output()
2755
        requester.set_headers({})
2756
        def stream_that_fails():
2757
            yield 'aaa'
2758
            yield 'bbb'
2759
            raise Exception('Boom!')
4022.1.8 by Robert Collins
Fix test_call_with_body_stream_error which was broken by a debugging change to still pass tests.
2760
        self.assertRaises(Exception, requester.call_with_body_stream,
2761
            ('one arg',), stream_that_fails())
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2762
        self.assertEquals(
2763
            'bzr message 3 (bzr 1.6)\n' # protocol version
2764
            '\x00\x00\x00\x02de' # headers
2765
            's\x00\x00\x00\x0bl7:one arge' # args
2766
            'b\x00\x00\x00\x03aaa' # body
2767
            'b\x00\x00\x00\x03bbb' # more body
2768
            'oE' # error flag
2769
            's\x00\x00\x00\x09l5:errore' # error args: ('error',)
2770
            'e', # end
2771
            output.getvalue())
2772
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.
2773
2774
class StubMediumRequest(object):
2775
    """A stub medium request that tracks the number of times accept_bytes is
2776
    called.
2777
    """
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2778
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.
2779
    def __init__(self):
2780
        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.
2781
        self._medium = 'dummy medium'
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2782
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.
2783
    def accept_bytes(self, bytes):
2784
        self.calls.append('accept_bytes')
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2785
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.
2786
    def finished_writing(self):
2787
        self.calls.append('finished_writing')
2788
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2789
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2790
interrupted_body_stream = (
2791
    'oS' # status flag (success)
2792
    's\x00\x00\x00\x08l4:argse' # args struct ('args,')
2793
    'b\x00\x00\x00\x03aaa' # body part ('aaa')
2794
    'b\x00\x00\x00\x03bbb' # body part ('bbb')
2795
    'oE' # status flag (error)
2796
    's\x00\x00\x00\x10l5:error5:Boom!e' # err struct ('error', 'Boom!')
2797
    'e' # EOM
2798
    )
2799
2800
3245.4.37 by Andrew Bennetts
Add test for sending ProtocolThreeResponder.send_error(UnknownSmartMethod(...)).
2801
class TestResponseEncodingProtocolThree(tests.TestCase):
2802
2803
    def make_response_encoder(self):
2804
        out_stream = StringIO()
2805
        response_encoder = protocol.ProtocolThreeResponder(out_stream.write)
2806
        return response_encoder, out_stream
2807
2808
    def test_send_error_unknown_method(self):
2809
        encoder, out_stream = self.make_response_encoder()
2810
        encoder.send_error(errors.UnknownSmartMethod('method name'))
2811
        # Use assertEndsWith so that we don't compare the header, which varies
2812
        # by bzrlib.__version__.
2813
        self.assertEndsWith(
2814
            out_stream.getvalue(),
2815
            # error status
2816
            'oE' +
2817
            # tuple: 'UnknownMethod', 'method name'
2818
            's\x00\x00\x00\x20l13:UnknownMethod11:method namee'
2819
            # end of message
2820
            'e')
2821
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
2822
    def test_send_broken_body_stream(self):
2823
        encoder, out_stream = self.make_response_encoder()
2824
        encoder._headers = {}
2825
        def stream_that_fails():
2826
            yield 'aaa'
2827
            yield 'bbb'
2828
            raise Exception('Boom!')
2829
        response = _mod_request.SuccessfulSmartServerResponse(
2830
            ('args',), body_stream=stream_that_fails())
2831
        encoder.send_response(response)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2832
        expected_response = (
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
2833
            'bzr message 3 (bzr 1.6)\n'  # protocol marker
2834
            '\x00\x00\x00\x02de' # headers dict (empty)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2835
            + interrupted_body_stream)
2836
        self.assertEqual(expected_response, out_stream.getvalue())
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
2837
3245.4.37 by Andrew Bennetts
Add test for sending ProtocolThreeResponder.send_error(UnknownSmartMethod(...)).
2838
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.
2839
class TestResponseEncoderBufferingProtocolThree(tests.TestCase):
2840
    """Tests for buffering of responses.
2841
2842
    We want to avoid doing many small writes when one would do, to avoid
2843
    unnecessary network overhead.
2844
    """
2845
2846
    def setUp(self):
2847
        self.writes = []
2848
        self.responder = protocol.ProtocolThreeResponder(self.writes.append)
2849
2850
    def assertWriteCount(self, expected_count):
2851
        self.assertEqual(
2852
            expected_count, len(self.writes),
2853
            "Too many writes: %r" % (self.writes,))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2854
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.
2855
    def test_send_error_writes_just_once(self):
2856
        """An error response is written to the medium all at once."""
2857
        self.responder.send_error(Exception('An exception string.'))
2858
        self.assertWriteCount(1)
2859
2860
    def test_send_response_writes_just_once(self):
2861
        """A normal response with no body is written to the medium all at once.
2862
        """
2863
        response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
2864
        self.responder.send_response(response)
2865
        self.assertWriteCount(1)
2866
2867
    def test_send_response_with_body_writes_just_once(self):
2868
        """A normal response with a monolithic body is written to the medium
2869
        all at once.
2870
        """
2871
        response = _mod_request.SuccessfulSmartServerResponse(
2872
            ('arg', 'arg'), body='body bytes')
2873
        self.responder.send_response(response)
2874
        self.assertWriteCount(1)
2875
4078.1.2 by Andrew Bennetts
Adjust write buffering tests for improved buffering.
2876
    def test_send_response_with_body_stream_buffers_writes(self):
2877
        """A normal response with a stream body writes to the medium once."""
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.
2878
        # Construct a response with stream with 2 chunks in it.
2879
        response = _mod_request.SuccessfulSmartServerResponse(
2880
            ('arg', 'arg'), body_stream=['chunk1', 'chunk2'])
2881
        self.responder.send_response(response)
4078.1.2 by Andrew Bennetts
Adjust write buffering tests for improved buffering.
2882
        # We will write just once, despite the multiple chunks, due to
2883
        # buffering.
2884
        self.assertWriteCount(1)
2885
2886
    def test_send_response_with_body_stream_flushes_buffers_sometimes(self):
2887
        """When there are many chunks (>100), multiple writes will occur rather
2888
        than buffering indefinitely.
2889
        """
2890
        # Construct a response with stream with 40 chunks in it.  Every chunk
2891
        # triggers 3 buffered writes, so we expect > 100 buffered writes, but <
2892
        # 200.
2893
        body_stream = ['chunk %d' % count for count in range(40)]
2894
        response = _mod_request.SuccessfulSmartServerResponse(
2895
            ('arg', 'arg'), body_stream=body_stream)
2896
        self.responder.send_response(response)
2897
        # The write buffer is flushed every 100 buffered writes, so we expect 2
2898
        # actual writes.
2899
        self.assertWriteCount(2)
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.
2900
2901
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.
2902
class TestSmartClientUnicode(tests.TestCase):
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2903
    """_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.
2904
2905
    Unicode arguments to call_with_body_bytes are not correct (remote method
2906
    names, arguments, and bodies must all be expressed as byte strings), but
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
2907
    _SmartClient should gracefully reject them, rather than getting into a
2908
    broken state that prevents future correct calls from working.  That is, it
2909
    should be possible to issue more requests on the medium afterwards, rather
2910
    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.
2911
    mysteriously fail with TooManyConcurrentRequests.
2912
    """
2913
2914
    def assertCallDoesNotBreakMedium(self, method, args, body):
2915
        """Call a medium with the given method, args and body, then assert that
2916
        the medium is left in a sane state, i.e. is capable of allowing further
2917
        requests.
2918
        """
2919
        input = StringIO("\n")
2920
        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.
2921
        client_medium = medium.SmartSimplePipesClientMedium(
2922
            input, output, 'ignored base')
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
2923
        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.
2924
        self.assertRaises(TypeError,
2925
            smart_client.call_with_body_bytes, method, args, body)
2926
        self.assertEqual("", output.getvalue())
2927
        self.assertEqual(None, client_medium._current_request)
2928
2929
    def test_call_with_body_bytes_unicode_method(self):
2930
        self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
2931
2932
    def test_call_with_body_bytes_unicode_args(self):
2933
        self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
2414.1.2 by Andrew Bennetts
Deal with review comments.
2934
        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.
2935
2936
    def test_call_with_body_bytes_unicode_body(self):
2937
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
2938
2939
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
2940
class MockMedium(medium.SmartClientMedium):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2941
    """A mock medium that can be used to test _SmartClient.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2942
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2943
    It can be given a series of requests to expect (and responses it should
2944
    return for them).  It can also be told when the client is expected to
2945
    disconnect a medium.  Expectations must be satisfied in the order they are
2946
    given, or else an AssertionError will be raised.
2947
2948
    Typical use looks like::
2949
2950
        medium = MockMedium()
2951
        medium.expect_request(...)
2952
        medium.expect_request(...)
2953
        medium.expect_request(...)
2954
    """
2955
2956
    def __init__(self):
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
2957
        super(MockMedium, self).__init__('dummy base')
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2958
        self._mock_request = _MockMediumRequest(self)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2959
        self._expected_events = []
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2960
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2961
    def expect_request(self, request_bytes, response_bytes,
2962
                       allow_partial_read=False):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2963
        """Expect 'request_bytes' to be sent, and reply with 'response_bytes'.
2964
2965
        No assumption is made about how many times accept_bytes should be
2966
        called to send the request.  Similarly, no assumption is made about how
2967
        many times read_bytes/read_line are called by protocol code to read a
2968
        response.  e.g.::
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2969
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2970
            request.accept_bytes('ab')
2971
            request.accept_bytes('cd')
2972
            request.finished_writing()
2973
2974
        and::
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2975
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2976
            request.accept_bytes('abcd')
2977
            request.finished_writing()
2978
2979
        Will both satisfy ``medium.expect_request('abcd', ...)``.  Thus tests
2980
        using this should not break due to irrelevant changes in protocol
2981
        implementations.
2982
2983
        :param allow_partial_read: if True, no assertion is raised if a
2984
            response is not fully read.  Setting this is useful when the client
2985
            is expected to disconnect without needing to read the complete
2986
            response.  Default is False.
2987
        """
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2988
        self._expected_events.append(('send request', request_bytes))
2989
        if allow_partial_read:
2990
            self._expected_events.append(
2991
                ('read response (partial)', response_bytes))
2992
        else:
2993
            self._expected_events.append(('read response', response_bytes))
2994
2995
    def expect_disconnect(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2996
        """Expect the client to call ``medium.disconnect()``."""
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
2997
        self._expected_events.append('disconnect')
2998
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
2999
    def _assertEvent(self, observed_event):
3000
        """Raise AssertionError unless observed_event matches the next expected
3001
        event.
3002
3003
        :seealso: expect_request
3004
        :seealso: expect_disconnect
3005
        """
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.
3006
        try:
3007
            expected_event = self._expected_events.pop(0)
3008
        except IndexError:
3009
            raise AssertionError(
3010
                'Mock medium observed event %r, but no more events expected'
3011
                % (observed_event,))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3012
        if expected_event[0] == 'read response (partial)':
3013
            if observed_event[0] != 'read response':
3014
                raise AssertionError(
3015
                    'Mock medium observed event %r, but expected event %r'
3016
                    % (observed_event, expected_event))
3017
        elif observed_event != expected_event:
3018
            raise AssertionError(
3019
                'Mock medium observed event %r, but expected event %r'
3020
                % (observed_event, expected_event))
3021
        if self._expected_events:
3022
            next_event = self._expected_events[0]
3023
            if next_event[0].startswith('read response'):
3024
                self._mock_request._response = next_event[1]
3025
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3026
    def get_request(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3027
        return self._mock_request
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3028
3029
    def disconnect(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3030
        if self._mock_request._read_bytes:
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3031
            self._assertEvent(('read response', self._mock_request._read_bytes))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3032
            self._mock_request._read_bytes = ''
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3033
        self._assertEvent('disconnect')
3034
3035
3036
class _MockMediumRequest(object):
3037
    """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.
3038
3039
    def __init__(self, mock_medium):
3040
        self._medium = mock_medium
3041
        self._written_bytes = ''
3042
        self._read_bytes = ''
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3043
        self._response = None
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3044
3045
    def accept_bytes(self, bytes):
3046
        self._written_bytes += bytes
3047
3048
    def finished_writing(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3049
        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.
3050
        self._written_bytes = ''
3051
3052
    def finished_reading(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3053
        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.
3054
        self._read_bytes = ''
3055
3056
    def read_bytes(self, size):
3057
        resp = self._response
3058
        bytes, resp = resp[:size], resp[size:]
3059
        self._response = resp
3060
        self._read_bytes += bytes
3061
        return bytes
3062
3063
    def read_line(self):
3064
        resp = self._response
3065
        try:
3066
            line, resp = resp.split('\n', 1)
3067
            line += '\n'
3068
        except ValueError:
3069
            line, resp = resp, ''
3070
        self._response = resp
3071
        self._read_bytes += line
3072
        return line
3073
3074
3075
class Test_SmartClientVersionDetection(tests.TestCase):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3076
    """Tests for _SmartClient's automatic protocol version detection.
3077
3078
    On the first remote call, _SmartClient will keep retrying the request with
3079
    different protocol versions until it finds one that works.
3080
    """
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3081
3082
    def test_version_three_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3083
        """With a protocol 3 server, only one request is needed."""
3084
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3085
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3086
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
3087
        medium.expect_request(
3088
            message_start +
3089
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3090
            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.
3091
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3092
        # The call succeeded without raising any exceptions from the mock
3093
        # 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.
3094
        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.
3095
        self.assertEqual([], medium._expected_events)
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
3096
        # Also, the v3 works then the server should be assumed to support RPCs
3097
        # introduced in 1.6.
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
3098
        self.assertFalse(medium._is_remote_before((1, 6)))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3099
3100
    def test_version_two_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3101
        """If the server only speaks protocol 2, the client will first try
3102
        version 3, then fallback to protocol 2.
3103
3104
        Further, _SmartClient caches the detection, so future requests will all
3105
        use protocol 2 immediately.
3106
        """
3107
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3108
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3109
        # First the client should send a v3 request, but the server will reply
3110
        # with a v2 error.
3111
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3112
            '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.
3113
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3114
            'bzr response 2\nfailed\n\n')
3115
        # So then the client should disconnect to reset the connection, because
3116
        # the client needs to assume the server cannot read any further
3117
        # requests off the original connection.
3118
        medium.expect_disconnect()
3119
        # The client should then retry the original request in v2
3120
        medium.expect_request(
3121
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
3122
            'bzr response 2\nsuccess\nresponse value\n')
3123
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
3124
        # The smart_client object will return the result of the successful
3125
        # query.
3126
        self.assertEqual(('response value',), result)
3127
3128
        # Now try another request, and this time the client will just use
3129
        # protocol 2.  (i.e. the autodetection won't be repeated)
3130
        medium.expect_request(
3131
            'bzr request 2\nanother-method\n',
3132
            'bzr response 2\nsuccess\nanother response\n')
3133
        result = smart_client.call('another-method')
3134
        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.
3135
        self.assertEqual([], medium._expected_events)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3136
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
3137
        # Also, because v3 is not supported, the client medium should assume
3138
        # that RPCs introduced in 1.6 aren't supported either.
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
3139
        self.assertTrue(medium._is_remote_before((1, 6)))
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
3140
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3141
    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.
3142
        """If the server does not use any known (or at least supported)
3143
        protocol version, a SmartProtocolError is raised.
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3144
        """
3145
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3146
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3147
        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.
3148
        # The client will try v3 and v2 before eventually giving up.
3149
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3150
            '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.
3151
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3152
            unknown_protocol_bytes)
3153
        medium.expect_disconnect()
3154
        medium.expect_request(
3155
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
3156
            unknown_protocol_bytes)
3157
        medium.expect_disconnect()
3158
        self.assertRaises(
3159
            errors.SmartProtocolError,
3160
            smart_client.call, 'method-name', 'arg 1', 'arg 2')
3161
        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.
3162
3163
    def test_first_response_is_error(self):
3164
        """If the server replies with an error, then the version detection
3165
        should be complete.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3166
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
3167
        This test is very similar to test_version_two_server, but catches a bug
3168
        we had in the case where the first reply was an error response.
3169
        """
3170
        medium = MockMedium()
3171
        smart_client = client._SmartClient(medium, headers={})
3172
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
3173
        # Issue a request that gets an error reply in a non-default protocol
3174
        # version.
3175
        medium.expect_request(
3176
            message_start +
3177
            's\x00\x00\x00\x10l11:method-nameee',
3178
            'bzr response 2\nfailed\n\n')
3179
        medium.expect_disconnect()
3180
        medium.expect_request(
3181
            'bzr request 2\nmethod-name\n',
3182
            'bzr response 2\nfailed\nFooBarError\n')
3183
        err = self.assertRaises(
3184
            errors.ErrorFromSmartServer,
3185
            smart_client.call, 'method-name')
3186
        self.assertEqual(('FooBarError',), err.error_tuple)
3187
        # Now the medium should have remembered the protocol version, so
3188
        # subsequent requests will use the remembered version immediately.
3189
        medium.expect_request(
3190
            'bzr request 2\nmethod-name\n',
3191
            'bzr response 2\nsuccess\nresponse value\n')
3192
        result = smart_client.call('method-name')
3193
        self.assertEqual(('response value',), result)
3194
        self.assertEqual([], medium._expected_events)
3195
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3196
3197
class Test_SmartClient(tests.TestCase):
3198
3199
    def test_call_default_headers(self):
3200
        """ProtocolThreeRequester.call by default sends a 'Software
3201
        version' header.
3202
        """
3431.3.4 by Andrew Bennetts
Revert now unnecessary test change from bzr.dev.
3203
        smart_client = client._SmartClient('dummy medium')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
3204
        self.assertEqual(
3205
            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.
3206
        # XXX: need a test that smart_client._headers is passed to the request
3207
        # encoder.
3208
3209
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3210
class LengthPrefixedBodyDecoder(tests.TestCase):
3211
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3212
    # XXX: TODO: make accept_reading_trailer invoke translate_response or
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
3213
    # something similar to the ProtocolBase method.
3214
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3215
    def test_construct(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
3216
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3217
        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.
3218
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3219
        self.assertEqual('', decoder.read_pending_data())
3220
        self.assertEqual('', decoder.unused_data)
3221
3222
    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
3223
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3224
        decoder.accept_bytes('')
3225
        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.
3226
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3227
        self.assertEqual('', decoder.read_pending_data())
3228
        self.assertEqual('', decoder.unused_data)
3229
        decoder.accept_bytes('7')
3230
        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.
3231
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3232
        self.assertEqual('', decoder.read_pending_data())
3233
        self.assertEqual('', decoder.unused_data)
3234
        decoder.accept_bytes('\na')
3235
        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.
3236
        self.assertEqual(11, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3237
        self.assertEqual('a', decoder.read_pending_data())
3238
        self.assertEqual('', decoder.unused_data)
3239
        decoder.accept_bytes('bcdefgd')
3240
        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.
3241
        self.assertEqual(4, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3242
        self.assertEqual('bcdefg', decoder.read_pending_data())
3243
        self.assertEqual('', decoder.unused_data)
3244
        decoder.accept_bytes('one')
3245
        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.
3246
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3247
        self.assertEqual('', decoder.read_pending_data())
3248
        self.assertEqual('', decoder.unused_data)
3249
        decoder.accept_bytes('\nblarg')
3250
        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.
3251
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3252
        self.assertEqual('', decoder.read_pending_data())
3253
        self.assertEqual('blarg', decoder.unused_data)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3254
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3255
    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
3256
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3257
        decoder.accept_bytes('1\nadone\nunused')
3258
        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.
3259
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3260
        self.assertEqual('a', decoder.read_pending_data())
3261
        self.assertEqual('unused', decoder.unused_data)
3262
3263
    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
3264
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3265
        decoder.accept_bytes('1\na')
3266
        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.
3267
        self.assertEqual(5, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3268
        self.assertEqual('a', decoder.read_pending_data())
3269
        self.assertEqual('', decoder.unused_data)
3270
        decoder.accept_bytes('done\n')
3271
        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.
3272
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3273
        self.assertEqual('', decoder.read_pending_data())
3274
        self.assertEqual('', decoder.unused_data)
3275
3276
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3277
class TestChunkedBodyDecoder(tests.TestCase):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3278
    """Tests for ChunkedBodyDecoder.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3279
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3280
    This is the body decoder used for protocol version two.
3281
    """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3282
3283
    def test_construct(self):
3284
        decoder = protocol.ChunkedBodyDecoder()
3285
        self.assertFalse(decoder.finished_reading)
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3286
        self.assertEqual(8, decoder.next_read_size())
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3287
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3288
        self.assertEqual('', decoder.unused_data)
3289
3290
    def test_empty_content(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3291
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
3292
        """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3293
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3294
        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.
3295
        decoder.accept_bytes('END\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3296
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3297
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3298
        self.assertEqual('', decoder.unused_data)
3299
3300
    def test_one_chunk(self):
3301
        """A body in a single chunk is decoded correctly."""
3302
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3303
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3304
        chunk_length = 'f\n'
3305
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3306
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3307
        decoder.accept_bytes(chunk_length + chunk_content + finish)
3308
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3309
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3310
        self.assertEqual('', decoder.unused_data)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3311
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3312
    def test_incomplete_chunk(self):
3313
        """When there are less bytes in the chunk than declared by the length,
3314
        then we haven't finished reading yet.
3315
        """
3316
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3317
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3318
        chunk_length = '8\n'
3319
        three_bytes = '123'
3320
        decoder.accept_bytes(chunk_length + three_bytes)
3321
        self.assertFalse(decoder.finished_reading)
3322
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3323
            5 + 4, decoder.next_read_size(),
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3324
            "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.
3325
            "this chunk plus 4 (the length of the end-of-body marker: "
3326
            "'END\\n')")
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3327
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3328
3329
    def test_incomplete_length(self):
3330
        """A chunk length hasn't been read until a newline byte has been read.
3331
        """
3332
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3333
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3334
        decoder.accept_bytes('9')
3335
        self.assertEqual(
3336
            1, decoder.next_read_size(),
3337
            "The next_read_size hint should be 1, because we don't know the "
3338
            "length yet.")
3339
        decoder.accept_bytes('\n')
3340
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3341
            9 + 4, decoder.next_read_size(),
3342
            "The next_read_size hint should be the length of the chunk plus 4 "
3343
            "(the length of the end-of-body marker: 'END\\n')")
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3344
        self.assertFalse(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3345
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3346
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3347
    def test_two_chunks(self):
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3348
        """Content from multiple chunks is concatenated."""
3349
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3350
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3351
        chunk_one = '3\naaa'
3352
        chunk_two = '5\nbbbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3353
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3354
        decoder.accept_bytes(chunk_one + chunk_two + finish)
3355
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3356
        self.assertEqual('aaa', decoder.read_next_chunk())
3357
        self.assertEqual('bbbbb', decoder.read_next_chunk())
3358
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3359
        self.assertEqual('', decoder.unused_data)
3360
3361
    def test_excess_bytes(self):
3362
        """Bytes after the chunked body are reported as unused bytes."""
3363
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3364
        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.
3365
        chunked_body = "5\naaaaaEND\n"
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3366
        excess_bytes = "excess bytes"
3367
        decoder.accept_bytes(chunked_body + excess_bytes)
3368
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3369
        self.assertEqual('aaaaa', decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3370
        self.assertEqual(excess_bytes, decoder.unused_data)
3371
        self.assertEqual(
3372
            1, decoder.next_read_size(),
3373
            "next_read_size hint should be 1 when finished_reading.")
3374
3375
    def test_multidigit_length(self):
3376
        """Lengths in the chunk prefixes can have multiple digits."""
3377
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3378
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3379
        length = 0x123
3380
        chunk_prefix = hex(length) + '\n'
3381
        chunk_bytes = 'z' * length
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3382
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3383
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
3384
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3385
        self.assertEqual(chunk_bytes, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3386
3387
    def test_byte_at_a_time(self):
3388
        """A complete body fed to the decoder one byte at a time should not
3389
        confuse the decoder.  That is, it should give the same result as if the
3390
        bytes had been received in one batch.
3391
3392
        This test is the same as test_one_chunk apart from the way accept_bytes
3393
        is called.
3394
        """
3395
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3396
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3397
        chunk_length = 'f\n'
3398
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3399
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3400
        for byte in (chunk_length + chunk_content + finish):
3401
            decoder.accept_bytes(byte)
3402
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3403
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3404
        self.assertEqual('', decoder.unused_data)
3405
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3406
    def test_read_pending_data_resets(self):
3407
        """read_pending_data does not return the same bytes twice."""
3408
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3409
        decoder.accept_bytes('chunked\n')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3410
        chunk_one = '3\naaa'
3411
        chunk_two = '3\nbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
3412
        finish = 'END\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3413
        decoder.accept_bytes(chunk_one)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3414
        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.
3415
        decoder.accept_bytes(chunk_two)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3416
        self.assertEqual('bbb', decoder.read_next_chunk())
3417
        self.assertEqual(None, decoder.read_next_chunk())
3418
3419
    def test_decode_error(self):
3420
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3421
        decoder.accept_bytes('chunked\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3422
        chunk_one = 'b\nfirst chunk'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3423
        error_signal = 'ERR\n'
3424
        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.
3425
        finish = 'END\n'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3426
        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.
3427
        self.assertTrue(decoder.finished_reading)
3428
        self.assertEqual('first chunk', decoder.read_next_chunk())
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3429
        expected_failure = _mod_request.FailedSmartServerResponse(
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
3430
            ('part1', 'part2'))
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
3431
        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.
3432
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3433
    def test_bad_header(self):
3434
        """accept_bytes raises a SmartProtocolError if a chunked body does not
3435
        start with the right header.
3436
        """
3437
        decoder = protocol.ChunkedBodyDecoder()
3438
        self.assertRaises(
3439
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
3440
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3441
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3442
class TestSuccessfulSmartServerResponse(tests.TestCase):
3443
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3444
    def test_construct_no_body(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3445
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3446
        self.assertEqual(('foo', 'bar'), response.args)
3447
        self.assertEqual(None, response.body)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3448
3449
    def test_construct_with_body(self):
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3450
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'),
3451
                                                              'bytes')
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3452
        self.assertEqual(('foo', 'bar'), response.args)
3453
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
3454
        # repr(response) doesn't trigger exceptions.
3455
        repr(response)
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3456
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3457
    def test_construct_with_body_stream(self):
3458
        bytes_iterable = ['abc']
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3459
        response = _mod_request.SuccessfulSmartServerResponse(
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3460
            ('foo', 'bar'), body_stream=bytes_iterable)
3461
        self.assertEqual(('foo', 'bar'), response.args)
3462
        self.assertEqual(bytes_iterable, response.body_stream)
3463
3464
    def test_construct_rejects_body_and_body_stream(self):
3465
        """'body' and 'body_stream' are mutually exclusive."""
3466
        self.assertRaises(
3467
            errors.BzrError,
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
3468
            _mod_request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
3469
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3470
    def test_is_successful(self):
3471
        """is_successful should return True for SuccessfulSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3472
        response = _mod_request.SuccessfulSmartServerResponse(('error',))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3473
        self.assertEqual(True, response.is_successful())
3474
3475
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3476
class TestFailedSmartServerResponse(tests.TestCase):
3477
3478
    def test_construct(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3479
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3480
        self.assertEqual(('foo', 'bar'), response.args)
3481
        self.assertEqual(None, response.body)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3482
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3483
        self.assertEqual(('foo', 'bar'), response.args)
3484
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
3485
        # repr(response) doesn't trigger exceptions.
3486
        repr(response)
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3487
3488
    def test_is_successful(self):
3489
        """is_successful should return False for FailedSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
3490
        response = _mod_request.FailedSmartServerResponse(('error',))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
3491
        self.assertEqual(False, response.is_successful())
3492
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
3493
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3494
class FakeHTTPMedium(object):
3495
    def __init__(self):
3496
        self.written_request = None
3497
        self._current_request = None
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
3498
    def send_http_smart_request(self, bytes):
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3499
        self.written_request = bytes
3500
        return None
3501
3502
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
3503
class HTTPTunnellingSmokeTest(tests.TestCase):
3504
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)
3505
    def setUp(self):
3506
        super(HTTPTunnellingSmokeTest, self).setUp()
3507
        # We use the VFS layer as part of HTTP tunnelling tests.
2402.1.2 by Andrew Bennetts
Deal with review comments.
3508
        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)
3509
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3510
    def test_smart_http_medium_request_accept_bytes(self):
3511
        medium = FakeHTTPMedium()
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
3512
        request = SmartClientHTTPMediumRequest(medium)
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
3513
        request.accept_bytes('abc')
3514
        request.accept_bytes('def')
3515
        self.assertEqual(None, medium.written_request)
3516
        request.finished_writing()
3517
        self.assertEqual('abcdef', medium.written_request)
3518
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.
3519
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
3520
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.
3521
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
3522
    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.
3523
        # 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')).
3524
        # requests for child URLs of that to the original URL.  i.e., we want to
3525
        # POST to "bzr+http://host/foo/.bzr/smart" and never something like
3526
        # "bzr+http://host/foo/.bzr/branch/.bzr/smart".  So, a cloned
3878.4.6 by Vincent Ladeuil
Fix bug #270863 by preserving 'bzr+http[s]' decorator.
3527
        # RemoteHTTPTransport remembers the initial URL, and adjusts the
3528
        # relpaths it sends in smart requests accordingly.
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
3529
        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.
3530
        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')).
3531
        self.assertEqual(base_transport._http_transport,
3532
                         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.
3533
        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.
3534
        self.assertEqual(
3535
            'child_dir/',
3536
            new_transport._client.remote_path_from_transport(new_transport))
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
3537
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
3538
    def test_remote_path_unnormal_base(self):
3539
        # If the transport's base isn't normalised, the _remote_path should
3540
        # still be calculated correctly.
3541
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
3542
        self.assertEqual('c', base_transport._remote_path('c'))
3543
3544
    def test_clone_unnormal_base(self):
3545
        # If the transport's base isn't normalised, cloned transports should
3546
        # still work correctly.
3547
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
3548
        new_transport = base_transport.clone('c')
3549
        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.
3550
        self.assertEqual(
3551
            'c/',
3552
            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.
3553
3878.4.6 by Vincent Ladeuil
Fix bug #270863 by preserving 'bzr+http[s]' decorator.
3554
    def test__redirect_to(self):
3555
        t = remote.RemoteHTTPTransport('bzr+http://www.example.com/foo')
3556
        r = t._redirected_to('http://www.example.com/foo',
3557
                             'http://www.example.com/bar')
3558
        self.assertEquals(type(r), type(t))
3559
3560
    def test__redirect_sibling_protocol(self):
3561
        t = remote.RemoteHTTPTransport('bzr+http://www.example.com/foo')
3562
        r = t._redirected_to('http://www.example.com/foo',
3563
                             'https://www.example.com/bar')
3564
        self.assertEquals(type(r), type(t))
3565
        self.assertStartsWith(r.base, 'bzr+https')
3566
3567
    def test__redirect_to_with_user(self):
3568
        t = remote.RemoteHTTPTransport('bzr+http://joe@www.example.com/foo')
3569
        r = t._redirected_to('http://www.example.com/foo',
3570
                             'http://www.example.com/bar')
3571
        self.assertEquals(type(r), type(t))
3572
        self.assertEquals('joe', t._user)
3573
        self.assertEquals(t._user, r._user)
3574
3575
    def test_redirected_to_same_host_different_protocol(self):
3576
        t = remote.RemoteHTTPTransport('bzr+http://joe@www.example.com/foo')
3577
        r = t._redirected_to('http://www.example.com/foo',
3578
                             'ftp://www.example.com/foo')
3579
        self.assertNotEquals(type(r), type(t))
3580
3581