~bzr-pqm/bzr/bzr.dev

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