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