~bzr-pqm/bzr/bzr.dev

4988.10.5 by John Arbash Meinel
Merge bzr.dev 5021 to resolve NEWS
1
# Copyright (C) 2006-2010 Canonical Ltd
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
16
17
"""Tests for smart transport"""
18
19
# all of this deals with byte strings so this is safe
20
from cStringIO import StringIO
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
21
import os
22
import socket
23
import threading
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
24
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
25
import bzrlib
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
26
from bzrlib import (
27
        bzrdir,
28
        errors,
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
29
        osutils,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
30
        tests,
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
31
        transport,
2049.1.1 by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes.
32
        urlutils,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
33
        )
2018.5.21 by Andrew Bennetts
Move bzrlib.transport.smart to bzrlib.smart
34
from bzrlib.smart import (
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
35
        client,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
36
        medium,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
37
        message,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
38
        protocol,
2432.4.3 by Robert Collins
Refactor the HPSS Response code to take SmartServerResponse rather than args and body.
39
        request as _mod_request,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
40
        server,
41
        vfs,
42
)
5247.2.10 by Vincent Ladeuil
Use SmartTCPServer_for_testing instead of SmartTCPServer (broken).
43
from bzrlib.tests import (
44
    test_smart,
5247.3.47 by Vincent Ladeuil
Use SmartTCPServer_for_testing for TestSmartTCPServer.test_get_error_unexpected.
45
    test_server,
5247.2.10 by Vincent Ladeuil
Use SmartTCPServer_for_testing instead of SmartTCPServer (broken).
46
    )
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
47
from bzrlib.transport import (
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
48
        http,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
49
        local,
50
        memory,
2400.1.1 by Andrew Bennetts
Rename bzrlib/transport/smart.py to bzrlib/transport/remote.py.
51
        remote,
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
52
        ssh,
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
53
        )
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
54
55
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
56
class StringIOSSHVendor(object):
57
    """A SSH vendor that uses StringIO to buffer writes and answer reads."""
58
59
    def __init__(self, read_from, write_to):
60
        self.read_from = read_from
61
        self.write_to = write_to
62
        self.calls = []
63
64
    def connect_ssh(self, username, password, host, port, command):
65
        self.calls.append(('connect_ssh', username, password, host, port,
66
            command))
67
        return StringIOSSHConnection(self)
68
69
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
70
class StringIOSSHConnection(ssh.SSHConnection):
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
71
    """A SSH connection that uses StringIO to buffer writes and answer reads."""
72
73
    def __init__(self, vendor):
74
        self.vendor = vendor
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
75
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
76
    def close(self):
77
        self.vendor.calls.append(('close', ))
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
78
        self.vendor.read_from.close()
79
        self.vendor.write_to.close()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
80
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
81
    def get_sock_or_pipes(self):
82
        return 'pipes', (self.vendor.read_from, self.vendor.write_to)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
83
84
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
85
class _InvalidHostnameFeature(tests.Feature):
86
    """Does 'non_existent.invalid' fail to resolve?
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
87
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
88
    RFC 2606 states that .invalid is reserved for invalid domain names, and
89
    also underscores are not a valid character in domain names.  Despite this,
90
    it's possible a badly misconfigured name server might decide to always
91
    return an address for any name, so this feature allows us to distinguish a
92
    broken system from a broken test.
93
    """
94
95
    def _probe(self):
96
        try:
97
            socket.gethostbyname('non_existent.invalid')
98
        except socket.gaierror:
99
            # The host name failed to resolve.  Good.
100
            return True
101
        else:
102
            return False
103
104
    def feature_name(self):
105
        return 'invalid hostname'
106
107
InvalidHostnameFeature = _InvalidHostnameFeature()
108
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
109
110
class SmartClientMediumTests(tests.TestCase):
111
    """Tests for SmartClientMedium.
112
113
    We should create a test scenario for this: we need a server module that
114
    construct the test-servers (like make_loopsocket_and_medium), and the list
115
    of SmartClientMedium classes to test.
116
    """
117
118
    def make_loopsocket_and_medium(self):
119
        """Create a loopback socket for testing, and a medium aimed at it."""
120
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
121
        sock.bind(('127.0.0.1', 0))
122
        sock.listen(1)
123
        port = sock.getsockname()[1]
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
124
        client_medium = medium.SmartTCPClientMedium('127.0.0.1', port, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
125
        return sock, client_medium
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
126
127
    def receive_bytes_on_server(self, sock, bytes):
128
        """Accept a connection on sock and read 3 bytes.
129
130
        The bytes are appended to the list bytes.
131
132
        :return: a Thread which is running to do the accept and recv.
133
        """
134
        def _receive_bytes_on_server():
135
            connection, address = sock.accept()
5011.3.11 by Andrew Bennetts
Consolidate changes, try to minimise unnecessary changes and tidy up those that kept.
136
            bytes.append(osutils.recv_all(connection, 3))
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
137
            connection.close()
138
        t = threading.Thread(target=_receive_bytes_on_server)
139
        t.start()
140
        return t
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
141
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
142
    def test_construct_smart_simple_pipes_client_medium(self):
143
        # the SimplePipes client medium takes two pipes:
144
        # readable pipe, writeable pipe.
145
        # Constructing one should just save these and do nothing.
146
        # We test this by passing in None.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
147
        client_medium = medium.SmartSimplePipesClientMedium(None, None, None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
148
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
149
    def test_simple_pipes_client_request_type(self):
150
        # SimplePipesClient should use SmartClientStreamMediumRequest's.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
151
        client_medium = medium.SmartSimplePipesClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
152
        request = client_medium.get_request()
153
        self.assertIsInstance(request, medium.SmartClientStreamMediumRequest)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
154
155
    def test_simple_pipes_client_get_concurrent_requests(self):
156
        # the simple_pipes client does not support pipelined requests:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
157
        # but it does support serial requests: we construct one after
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
158
        # another is finished. This is a smoke test testing the integration
159
        # of the SmartClientStreamMediumRequest and the SmartClientStreamMedium
160
        # classes - as the sibling classes share this logic, they do not have
161
        # explicit tests for this.
162
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
163
        client_medium = medium.SmartSimplePipesClientMedium(
164
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
165
        request = client_medium.get_request()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
166
        request.finished_writing()
167
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
168
        request2 = client_medium.get_request()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
169
        request2.finished_writing()
170
        request2.finished_reading()
171
172
    def test_simple_pipes_client__accept_bytes_writes_to_writable(self):
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
173
        # accept_bytes writes to the writeable pipe.
174
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
175
        client_medium = medium.SmartSimplePipesClientMedium(
176
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
177
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
178
        self.assertEqual('abc', output.getvalue())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
179
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
180
    def test_simple_pipes_client_disconnect_does_nothing(self):
181
        # calling disconnect does nothing.
182
        input = StringIO()
183
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
184
        client_medium = medium.SmartSimplePipesClientMedium(
185
            input, output, 'base')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
186
        # send some bytes to ensure disconnecting after activity still does not
187
        # close.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
188
        client_medium._accept_bytes('abc')
189
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
190
        self.assertFalse(input.closed)
191
        self.assertFalse(output.closed)
192
193
    def test_simple_pipes_client_accept_bytes_after_disconnect(self):
194
        # calling disconnect on the client does not alter the pipe that
195
        # accept_bytes writes to.
196
        input = StringIO()
197
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
198
        client_medium = medium.SmartSimplePipesClientMedium(
199
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
200
        client_medium._accept_bytes('abc')
201
        client_medium.disconnect()
202
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
203
        self.assertFalse(input.closed)
204
        self.assertFalse(output.closed)
205
        self.assertEqual('abcabc', output.getvalue())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
206
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
207
    def test_simple_pipes_client_ignores_disconnect_when_not_connected(self):
208
        # Doing a disconnect on a new (and thus unconnected) SimplePipes medium
209
        # does nothing.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
210
        client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
211
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
212
213
    def test_simple_pipes_client_can_always_read(self):
214
        # SmartSimplePipesClientMedium is never disconnected, so read_bytes
215
        # always tries to read from the underlying pipe.
216
        input = StringIO('abcdef')
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
217
        client_medium = medium.SmartSimplePipesClientMedium(input, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
218
        self.assertEqual('abc', client_medium.read_bytes(3))
219
        client_medium.disconnect()
220
        self.assertEqual('def', client_medium.read_bytes(3))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
221
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
222
    def test_simple_pipes_client_supports__flush(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
223
        # invoking _flush on a SimplePipesClient should flush the output
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
224
        # pipe. We test this by creating an output pipe that records
225
        # flush calls made to it.
226
        from StringIO import StringIO # get regular StringIO
227
        input = StringIO()
228
        output = StringIO()
229
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
230
        def logging_flush(): flush_calls.append('flush')
231
        output.flush = logging_flush
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
232
        client_medium = medium.SmartSimplePipesClientMedium(
233
            input, output, 'base')
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
234
        # this call is here to ensure we only flush once, not on every
235
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
236
        client_medium._accept_bytes('abc')
237
        client_medium._flush()
238
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
239
        self.assertEqual(['flush'], flush_calls)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
240
241
    def test_construct_smart_ssh_client_medium(self):
242
        # the SSH client medium takes:
243
        # host, port, username, password, vendor
244
        # Constructing one should just save these and do nothing.
245
        # we test this by creating a empty bound socket and constructing
246
        # a medium.
247
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
248
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
249
        unopened_port = sock.getsockname()[1]
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
250
        # having vendor be invalid means that if it tries to connect via the
251
        # vendor it will blow up.
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
252
        ssh_params = medium.SSHParams('127.0.0.1', unopened_port, None, None)
253
        client_medium = medium.SmartSSHClientMedium(
254
            'base', ssh_params, "not a vendor")
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
255
        sock.close()
256
257
    def test_ssh_client_connects_on_first_use(self):
258
        # The only thing that initiates a connection from the medium is giving
259
        # it bytes.
260
        output = StringIO()
261
        vendor = StringIOSSHVendor(StringIO(), output)
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
262
        ssh_params = medium.SSHParams(
263
            'a hostname', 'a port', 'a username', 'a password', 'bzr')
264
        client_medium = medium.SmartSSHClientMedium('base', ssh_params, vendor)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
265
        client_medium._accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
266
        self.assertEqual('abc', output.getvalue())
267
        self.assertEqual([('connect_ssh', 'a username', 'a password',
268
            'a hostname', 'a port',
269
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes'])],
270
            vendor.calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
271
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
272
    def test_ssh_client_changes_command_when_bzr_remote_path_passed(self):
273
        # The only thing that initiates a connection from the medium is giving
274
        # it bytes.
275
        output = StringIO()
276
        vendor = StringIOSSHVendor(StringIO(), output)
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
277
        ssh_params = medium.SSHParams(
278
            'a hostname', 'a port', 'a username', 'a password',
279
            bzr_remote_path='fugly')
280
        client_medium = medium.SmartSSHClientMedium('base', ssh_params, vendor)
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
281
        client_medium._accept_bytes('abc')
282
        self.assertEqual('abc', output.getvalue())
283
        self.assertEqual([('connect_ssh', 'a username', 'a password',
284
            'a hostname', 'a port',
285
            ['fugly', 'serve', '--inet', '--directory=/', '--allow-writes'])],
286
            vendor.calls)
287
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
288
    def test_ssh_client_disconnect_does_so(self):
289
        # calling disconnect should disconnect both the read_from and write_to
290
        # file-like object it from the ssh connection.
291
        input = StringIO()
292
        output = StringIO()
293
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
294
        client_medium = medium.SmartSSHClientMedium(
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
295
            'base', medium.SSHParams('a hostname'), vendor)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
296
        client_medium._accept_bytes('abc')
297
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
298
        self.assertTrue(input.closed)
299
        self.assertTrue(output.closed)
300
        self.assertEqual([
301
            ('connect_ssh', None, None, 'a hostname', None,
302
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
303
            ('close', ),
304
            ],
305
            vendor.calls)
306
307
    def test_ssh_client_disconnect_allows_reconnection(self):
308
        # calling disconnect on the client terminates the connection, but should
309
        # not prevent additional connections occuring.
310
        # we test this by initiating a second connection after doing a
311
        # disconnect.
312
        input = StringIO()
313
        output = StringIO()
314
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
315
        client_medium = medium.SmartSSHClientMedium(
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
316
            'base', medium.SSHParams('a hostname'), vendor)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
317
        client_medium._accept_bytes('abc')
318
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
319
        # the disconnect has closed output, so we need a new output for the
320
        # new connection to write to.
321
        input2 = StringIO()
322
        output2 = StringIO()
323
        vendor.read_from = input2
324
        vendor.write_to = output2
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
325
        client_medium._accept_bytes('abc')
326
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
327
        self.assertTrue(input.closed)
328
        self.assertTrue(output.closed)
329
        self.assertTrue(input2.closed)
330
        self.assertTrue(output2.closed)
331
        self.assertEqual([
332
            ('connect_ssh', None, None, 'a hostname', None,
333
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
334
            ('close', ),
335
            ('connect_ssh', None, None, 'a hostname', None,
336
            ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
337
            ('close', ),
338
            ],
339
            vendor.calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
340
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
341
    def test_ssh_client_ignores_disconnect_when_not_connected(self):
342
        # Doing a disconnect on a new (and thus unconnected) SSH medium
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
343
        # does not fail.  It's ok to disconnect an unconnected medium.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
344
        client_medium = medium.SmartSSHClientMedium(
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
345
            'base', medium.SSHParams(None))
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
346
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
347
348
    def test_ssh_client_raises_on_read_when_not_connected(self):
349
        # Doing a read on a new (and thus unconnected) SSH medium raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
350
        # MediumNotConnected.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
351
        client_medium = medium.SmartSSHClientMedium(
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
352
            'base', medium.SSHParams(None))
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
353
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
354
                          0)
355
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes,
356
                          1)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
357
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
358
    def test_ssh_client_supports__flush(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
359
        # invoking _flush on a SSHClientMedium should flush the output
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
360
        # pipe. We test this by creating an output pipe that records
361
        # flush calls made to it.
362
        from StringIO import StringIO # get regular StringIO
363
        input = StringIO()
364
        output = StringIO()
365
        flush_calls = []
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
366
        def logging_flush(): flush_calls.append('flush')
367
        output.flush = logging_flush
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
368
        vendor = StringIOSSHVendor(input, output)
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
369
        client_medium = medium.SmartSSHClientMedium(
5284.5.1 by Andrew Bennetts
Use socketpairs (rather than pipes) for SSH subprocesses where possible, and formalise some internal APIs a little more.
370
            'base', medium.SSHParams('a hostname'), vendor=vendor)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
371
        # this call is here to ensure we only flush once, not on every
372
        # _accept_bytes call.
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
373
        client_medium._accept_bytes('abc')
374
        client_medium._flush()
375
        client_medium.disconnect()
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
376
        self.assertEqual(['flush'], flush_calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
377
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
378
    def test_construct_smart_tcp_client_medium(self):
379
        # the TCP client medium takes a host and a port.  Constructing it won't
380
        # connect to anything.
381
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
382
        sock.bind(('127.0.0.1', 0))
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
383
        unopened_port = sock.getsockname()[1]
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
384
        client_medium = medium.SmartTCPClientMedium(
385
            '127.0.0.1', unopened_port, 'base')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
386
        sock.close()
387
388
    def test_tcp_client_connects_on_first_use(self):
389
        # The only thing that initiates a connection from the medium is giving
390
        # it bytes.
391
        sock, medium = self.make_loopsocket_and_medium()
392
        bytes = []
393
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
394
        medium.accept_bytes('abc')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
395
        t.join()
396
        sock.close()
397
        self.assertEqual(['abc'], bytes)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
398
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
399
    def test_tcp_client_disconnect_does_so(self):
400
        # calling disconnect on the client terminates the connection.
401
        # we test this by forcing a short read during a socket.MSG_WAITALL
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
402
        # call: write 2 bytes, try to read 3, and then the client disconnects.
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
403
        sock, medium = self.make_loopsocket_and_medium()
404
        bytes = []
405
        t = self.receive_bytes_on_server(sock, bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
406
        medium.accept_bytes('ab')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
407
        medium.disconnect()
408
        t.join()
409
        sock.close()
410
        self.assertEqual(['ab'], bytes)
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
411
        # now disconnect again: this should not do anything, if disconnection
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
412
        # really did disconnect.
413
        medium.disconnect()
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
414
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
415
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
416
    def test_tcp_client_ignores_disconnect_when_not_connected(self):
417
        # Doing a disconnect on a new (and thus unconnected) TCP medium
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
418
        # does not fail.  It's ok to disconnect an unconnected medium.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
419
        client_medium = medium.SmartTCPClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
420
        client_medium.disconnect()
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
421
422
    def test_tcp_client_raises_on_read_when_not_connected(self):
423
        # Doing a read on a new (and thus unconnected) TCP medium raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
424
        # MediumNotConnected.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
425
        client_medium = medium.SmartTCPClientMedium(None, None, None)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
426
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 0)
427
        self.assertRaises(errors.MediumNotConnected, client_medium.read_bytes, 1)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
428
429
    def test_tcp_client_supports__flush(self):
430
        # invoking _flush on a TCPClientMedium should do something useful.
431
        # RBC 20060922 not sure how to test/tell in this case.
432
        sock, medium = self.make_loopsocket_and_medium()
433
        bytes = []
434
        t = self.receive_bytes_on_server(sock, bytes)
435
        # try with nothing buffered
436
        medium._flush()
437
        medium._accept_bytes('ab')
438
        # and with something sent.
439
        medium._flush()
440
        medium.disconnect()
441
        t.join()
442
        sock.close()
443
        self.assertEqual(['ab'], bytes)
444
        # now disconnect again : this should not do anything, if disconnection
445
        # really did disconnect.
446
        medium.disconnect()
447
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
448
    def test_tcp_client_host_unknown_connection_error(self):
449
        self.requireFeature(InvalidHostnameFeature)
450
        client_medium = medium.SmartTCPClientMedium(
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
451
            'non_existent.invalid', 4155, 'base')
3180.1.2 by Andrew Bennetts
Add a test, and also add InvalidHostnameFeature.
452
        self.assertRaises(
453
            errors.ConnectionError, client_medium._ensure_connection)
454
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
455
456
class TestSmartClientStreamMediumRequest(tests.TestCase):
457
    """Tests the for SmartClientStreamMediumRequest.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
458
459
    SmartClientStreamMediumRequest is a helper for the three stream based
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
460
    mediums: TCP, SSH, SimplePipes, so we only test it once, and then test that
461
    those three mediums implement the interface it expects.
462
    """
463
464
    def test_accept_bytes_after_finished_writing_errors(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
465
        # calling accept_bytes after calling finished_writing raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
466
        # WritingCompleted to prevent bad assumptions on stream environments
467
        # breaking the needs of message-based environments.
468
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
469
        client_medium = medium.SmartSimplePipesClientMedium(
470
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
471
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
472
        request.finished_writing()
473
        self.assertRaises(errors.WritingCompleted, request.accept_bytes, None)
474
475
    def test_accept_bytes(self):
476
        # accept bytes should invoke _accept_bytes on the stream medium.
477
        # we test this by using the SimplePipes medium - the most trivial one
478
        # and checking that the pipes get the data.
479
        input = StringIO()
480
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
481
        client_medium = medium.SmartSimplePipesClientMedium(
482
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
483
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
484
        request.accept_bytes('123')
485
        request.finished_writing()
486
        request.finished_reading()
487
        self.assertEqual('', input.getvalue())
488
        self.assertEqual('123', output.getvalue())
489
490
    def test_construct_sets_stream_request(self):
491
        # constructing a SmartClientStreamMediumRequest on a StreamMedium sets
492
        # the current request to the new SmartClientStreamMediumRequest
493
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
494
        client_medium = medium.SmartSimplePipesClientMedium(
495
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
496
        request = medium.SmartClientStreamMediumRequest(client_medium)
497
        self.assertIs(client_medium._current_request, request)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
498
499
    def test_construct_while_another_request_active_throws(self):
500
        # constructing a SmartClientStreamMediumRequest on a StreamMedium with
501
        # a non-None _current_request raises TooManyConcurrentRequests.
502
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
503
        client_medium = medium.SmartSimplePipesClientMedium(
504
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
505
        client_medium._current_request = "a"
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
506
        self.assertRaises(errors.TooManyConcurrentRequests,
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
507
            medium.SmartClientStreamMediumRequest, client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
508
509
    def test_finished_read_clears_current_request(self):
510
        # calling finished_reading clears the current request from the requests
511
        # medium
512
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
513
        client_medium = medium.SmartSimplePipesClientMedium(
514
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
515
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
516
        request.finished_writing()
517
        request.finished_reading()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
518
        self.assertEqual(None, client_medium._current_request)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
519
520
    def test_finished_read_before_finished_write_errors(self):
521
        # calling finished_reading before calling finished_writing triggers a
522
        # WritingNotComplete error.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
523
        client_medium = medium.SmartSimplePipesClientMedium(
524
            None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
525
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
526
        self.assertRaises(errors.WritingNotComplete, request.finished_reading)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
527
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
528
    def test_read_bytes(self):
529
        # read bytes should invoke _read_bytes on the stream medium.
530
        # we test this by using the SimplePipes medium - the most trivial one
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
531
        # and checking that the data is supplied. Its possible that a
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
532
        # faulty implementation could poke at the pipe variables them selves,
533
        # but we trust that this will be caught as it will break the integration
534
        # smoke tests.
535
        input = StringIO('321')
536
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
537
        client_medium = medium.SmartSimplePipesClientMedium(
538
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
539
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
540
        request.finished_writing()
541
        self.assertEqual('321', request.read_bytes(3))
542
        request.finished_reading()
543
        self.assertEqual('', input.read())
544
        self.assertEqual('', output.getvalue())
545
546
    def test_read_bytes_before_finished_write_errors(self):
547
        # calling read_bytes before calling finished_writing triggers a
548
        # WritingNotComplete error because the Smart protocol is designed to be
549
        # compatible with strict message based protocols like HTTP where the
550
        # request cannot be submitted until the writing has completed.
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
551
        client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
552
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
553
        self.assertRaises(errors.WritingNotComplete, request.read_bytes, None)
554
555
    def test_read_bytes_after_finished_reading_errors(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
556
        # calling read_bytes after calling finished_reading raises
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
557
        # ReadingCompleted to prevent bad assumptions on stream environments
558
        # breaking the needs of message-based environments.
559
        output = StringIO()
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
560
        client_medium = medium.SmartSimplePipesClientMedium(
561
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
562
        request = medium.SmartClientStreamMediumRequest(client_medium)
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
563
        request.finished_writing()
564
        request.finished_reading()
565
        self.assertRaises(errors.ReadingCompleted, request.read_bytes, None)
566
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
567
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
568
class RemoteTransportTests(test_smart.TestCaseWithSmartMedium):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
569
570
    def test_plausible_url(self):
571
        self.assert_(self.get_url().startswith('bzr://'))
572
573
    def test_probe_transport(self):
574
        t = self.get_transport()
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
575
        self.assertIsInstance(t, remote.RemoteTransport)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
576
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
577
    def test_get_medium_from_transport(self):
578
        """Remote transport has a medium always, which it can return."""
579
        t = self.get_transport()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
580
        client_medium = t.get_smart_medium()
581
        self.assertIsInstance(client_medium, medium.SmartClientMedium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
582
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
583
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
584
class ErrorRaisingProtocol(object):
585
586
    def __init__(self, exception):
587
        self.exception = exception
588
589
    def next_read_size(self):
590
        raise self.exception
591
592
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
593
class SampleRequest(object):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
594
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
595
    def __init__(self, expected_bytes):
596
        self.accepted_bytes = ''
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
597
        self._finished_reading = False
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
598
        self.expected_bytes = expected_bytes
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
599
        self.unused_data = ''
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
600
601
    def accept_bytes(self, bytes):
602
        self.accepted_bytes += bytes
603
        if self.accepted_bytes.startswith(self.expected_bytes):
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
604
            self._finished_reading = True
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
605
            self.unused_data = self.accepted_bytes[len(self.expected_bytes):]
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
606
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
607
    def next_read_size(self):
608
        if self._finished_reading:
609
            return 0
610
        else:
611
            return 1
612
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
613
614
class TestSmartServerStreamMedium(tests.TestCase):
615
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
616
    def setUp(self):
617
        super(TestSmartServerStreamMedium, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
618
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
619
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
620
    def portable_socket_pair(self):
621
        """Return a pair of TCP sockets connected to each other.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
622
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
623
        Unlike socket.socketpair, this should work on Windows.
624
        """
625
        listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
626
        listen_sock.bind(('127.0.0.1', 0))
627
        listen_sock.listen(1)
628
        client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
629
        client_sock.connect(listen_sock.getsockname())
630
        server_sock, addr = listen_sock.accept()
631
        listen_sock.close()
632
        return server_sock, client_sock
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
633
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
634
    def test_smart_query_version(self):
635
        """Feed a canned query version to a server"""
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
636
        # wire-to-wire, using the whole stack
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
637
        to_server = StringIO('hello\n')
638
        from_server = StringIO()
2018.2.27 by Andrew Bennetts
Merge from bzr.dev
639
        transport = local.LocalTransport(urlutils.local_path_to_url('/'))
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
640
        server = medium.SmartServerPipeStreamMedium(
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
641
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
642
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
643
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
644
        server._serve_one_request(smart_protocol)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
645
        self.assertEqual('ok\0012\n',
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
646
                         from_server.getvalue())
647
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
648
    def test_response_to_canned_get(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
649
        transport = memory.MemoryTransport('memory:///')
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
650
        transport.put_bytes('testfile', 'contents\nof\nfile\n')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
651
        to_server = StringIO('get\001./testfile\n')
652
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
653
        server = medium.SmartServerPipeStreamMedium(
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
654
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
655
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
656
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
657
        server._serve_one_request(smart_protocol)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
658
        self.assertEqual('ok\n'
659
                         '17\n'
660
                         'contents\nof\nfile\n'
661
                         'done\n',
662
                         from_server.getvalue())
663
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
664
    def test_response_to_canned_get_of_utf8(self):
665
        # wire-to-wire, using the whole stack, with a UTF-8 filename.
666
        transport = memory.MemoryTransport('memory:///')
667
        utf8_filename = u'testfile\N{INTERROBANG}'.encode('utf-8')
4760.2.4 by Andrew Bennetts
Update test_response_to_canned_get_of_utf8 to reflect reality.
668
        # VFS requests use filenames, not raw UTF-8.
669
        hpss_path = urlutils.escape(utf8_filename)
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
670
        transport.put_bytes(utf8_filename, 'contents\nof\nfile\n')
4760.2.4 by Andrew Bennetts
Update test_response_to_canned_get_of_utf8 to reflect reality.
671
        to_server = StringIO('get\001' + hpss_path + '\n')
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
672
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
673
        server = medium.SmartServerPipeStreamMedium(
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
674
            to_server, from_server, transport)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
675
        smart_protocol = protocol.SmartServerRequestProtocolOne(transport,
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
676
                from_server.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
677
        server._serve_one_request(smart_protocol)
2018.2.31 by Andrew Bennetts
Fix dispatching of smart server requests involving unicode paths.
678
        self.assertEqual('ok\n'
679
                         '17\n'
680
                         'contents\nof\nfile\n'
681
                         'done\n',
682
                         from_server.getvalue())
683
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
684
    def test_pipe_like_stream_with_bulk_data(self):
685
        sample_request_bytes = 'command\n9\nbulk datadone\n'
686
        to_server = StringIO(sample_request_bytes)
687
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
688
        server = medium.SmartServerPipeStreamMedium(
689
            to_server, from_server, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
690
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
691
        server._serve_one_request(sample_protocol)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
692
        self.assertEqual('', from_server.getvalue())
693
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
694
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
695
696
    def test_socket_stream_with_bulk_data(self):
697
        sample_request_bytes = 'command\n9\nbulk datadone\n'
698
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
699
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
700
            server_sock, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
701
        sample_protocol = SampleRequest(expected_bytes=sample_request_bytes)
702
        client_sock.sendall(sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
703
        server._serve_one_request(sample_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
704
        server_sock.close()
705
        self.assertEqual('', client_sock.recv(1))
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
706
        self.assertEqual(sample_request_bytes, sample_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
707
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
708
709
    def test_pipe_like_stream_shutdown_detection(self):
710
        to_server = StringIO('')
711
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
712
        server = medium.SmartServerPipeStreamMedium(to_server, from_server, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
713
        server._serve_one_request(SampleRequest('x'))
714
        self.assertTrue(server.finished)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
715
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
716
    def test_socket_stream_shutdown_detection(self):
717
        server_sock, client_sock = self.portable_socket_pair()
718
        client_sock.close()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
719
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
720
            server_sock, None)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
721
        server._serve_one_request(SampleRequest('x'))
722
        self.assertTrue(server.finished)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
723
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
724
    def test_socket_stream_incomplete_request(self):
725
        """The medium should still construct the right protocol version even if
726
        the initial read only reads part of the request.
727
728
        Specifically, it should correctly read the protocol version line even
729
        if the partial read doesn't end in a newline.  An older, naive
730
        implementation of _get_line in the server used to have a bug in that
731
        case.
732
        """
733
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
734
        rest_of_request_bytes = 'lo\n'
735
        expected_response = (
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
736
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
737
        server_sock, client_sock = self.portable_socket_pair()
738
        server = medium.SmartServerSocketStreamMedium(
739
            server_sock, None)
740
        client_sock.sendall(incomplete_request_bytes)
741
        server_protocol = server._build_protocol()
742
        client_sock.sendall(rest_of_request_bytes)
743
        server._serve_one_request(server_protocol)
744
        server_sock.close()
5011.3.11 by Andrew Bennetts
Consolidate changes, try to minimise unnecessary changes and tidy up those that kept.
745
        self.assertEqual(expected_response, osutils.recv_all(client_sock, 50),
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
746
                         "Not a version 2 response to 'hello' request.")
747
        self.assertEqual('', client_sock.recv(1))
748
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
749
    def test_pipe_stream_incomplete_request(self):
750
        """The medium should still construct the right protocol version even if
751
        the initial read only reads part of the request.
752
753
        Specifically, it should correctly read the protocol version line even
754
        if the partial read doesn't end in a newline.  An older, naive
755
        implementation of _get_line in the server used to have a bug in that
756
        case.
757
        """
758
        incomplete_request_bytes = protocol.REQUEST_VERSION_TWO + 'hel'
759
        rest_of_request_bytes = 'lo\n'
760
        expected_response = (
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
761
            protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n')
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
762
        # Make a pair of pipes, to and from the server
763
        to_server, to_server_w = os.pipe()
764
        from_server_r, from_server = os.pipe()
765
        to_server = os.fdopen(to_server, 'r', 0)
766
        to_server_w = os.fdopen(to_server_w, 'w', 0)
767
        from_server_r = os.fdopen(from_server_r, 'r', 0)
768
        from_server = os.fdopen(from_server, 'w', 0)
769
        server = medium.SmartServerPipeStreamMedium(
770
            to_server, from_server, None)
771
        # Like test_socket_stream_incomplete_request, write an incomplete
772
        # request (that does not end in '\n') and build a protocol from it.
773
        to_server_w.write(incomplete_request_bytes)
774
        server_protocol = server._build_protocol()
775
        # Send the rest of the request, and finish serving it.
776
        to_server_w.write(rest_of_request_bytes)
777
        server._serve_one_request(server_protocol)
778
        to_server_w.close()
779
        from_server.close()
780
        self.assertEqual(expected_response, from_server_r.read(),
781
                         "Not a version 2 response to 'hello' request.")
782
        self.assertEqual('', from_server_r.read(1))
783
        from_server_r.close()
784
        to_server.close()
785
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
786
    def test_pipe_like_stream_with_two_requests(self):
787
        # If two requests are read in one go, then two calls to
788
        # _serve_one_request should still process both of them as if they had
4031.3.1 by Frank Aspell
Fixing various typos
789
        # been received separately.
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
790
        sample_request_bytes = 'command\n'
791
        to_server = StringIO(sample_request_bytes * 2)
792
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
793
        server = medium.SmartServerPipeStreamMedium(
794
            to_server, from_server, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
795
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
796
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
797
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
798
        self.assertEqual('', from_server.getvalue())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
799
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
800
        # Make a new protocol, call _serve_one_request with it to collect the
801
        # second request.
802
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
803
        server._serve_one_request(second_protocol)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
804
        self.assertEqual('', from_server.getvalue())
805
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
806
        self.assertFalse(server.finished)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
807
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
808
    def test_socket_stream_with_two_requests(self):
809
        # If two requests are read in one go, then two calls to
810
        # _serve_one_request should still process both of them as if they had
4031.3.1 by Frank Aspell
Fixing various typos
811
        # been received separately.
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
812
        sample_request_bytes = 'command\n'
813
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
814
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
815
            server_sock, None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
816
        first_protocol = SampleRequest(expected_bytes=sample_request_bytes)
817
        # Put two whole requests on the wire.
818
        client_sock.sendall(sample_request_bytes * 2)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
819
        server._serve_one_request(first_protocol)
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
820
        self.assertEqual(0, first_protocol.next_read_size())
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
821
        self.assertFalse(server.finished)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
822
        # Make a new protocol, call _serve_one_request with it to collect the
823
        # second request.
824
        second_protocol = SampleRequest(expected_bytes=sample_request_bytes)
825
        stream_still_open = server._serve_one_request(second_protocol)
826
        self.assertEqual(sample_request_bytes, second_protocol.accepted_bytes)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
827
        self.assertFalse(server.finished)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
828
        server_sock.close()
829
        self.assertEqual('', client_sock.recv(1))
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
830
831
    def test_pipe_like_stream_error_handling(self):
832
        # Use plain python StringIO so we can monkey-patch the close method to
833
        # not discard the contents.
834
        from StringIO import StringIO
835
        to_server = StringIO('')
836
        from_server = StringIO()
837
        self.closed = False
838
        def close():
839
            self.closed = True
840
        from_server.close = close
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
841
        server = medium.SmartServerPipeStreamMedium(
842
            to_server, from_server, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
843
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
844
        server._serve_one_request(fake_protocol)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
845
        self.assertEqual('', from_server.getvalue())
846
        self.assertTrue(self.closed)
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
847
        self.assertTrue(server.finished)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
848
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
849
    def test_socket_stream_error_handling(self):
850
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
851
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
852
            server_sock, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
853
        fake_protocol = ErrorRaisingProtocol(Exception('boom'))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
854
        server._serve_one_request(fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
855
        # recv should not block, because the other end of the socket has been
856
        # closed.
857
        self.assertEqual('', client_sock.recv(1))
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
858
        self.assertTrue(server.finished)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
859
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
860
    def test_pipe_like_stream_keyboard_interrupt_handling(self):
861
        to_server = StringIO('')
862
        from_server = StringIO()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
863
        server = medium.SmartServerPipeStreamMedium(
864
            to_server, from_server, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
865
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
866
        self.assertRaises(
867
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
868
        self.assertEqual('', from_server.getvalue())
869
870
    def test_socket_stream_keyboard_interrupt_handling(self):
871
        server_sock, client_sock = self.portable_socket_pair()
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
872
        server = medium.SmartServerSocketStreamMedium(
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
873
            server_sock, None)
2018.2.18 by Andrew Bennetts
Just close the pipe/socket if the medium catches an error, and add tests for medium exception handling.
874
        fake_protocol = ErrorRaisingProtocol(KeyboardInterrupt('boom'))
875
        self.assertRaises(
876
            KeyboardInterrupt, server._serve_one_request, fake_protocol)
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
877
        server_sock.close()
878
        self.assertEqual('', client_sock.recv(1))
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
879
880
    def build_protocol_pipe_like(self, bytes):
881
        to_server = StringIO(bytes)
882
        from_server = StringIO()
883
        server = medium.SmartServerPipeStreamMedium(
884
            to_server, from_server, None)
885
        return server._build_protocol()
886
887
    def build_protocol_socket(self, bytes):
888
        server_sock, client_sock = self.portable_socket_pair()
889
        server = medium.SmartServerSocketStreamMedium(
890
            server_sock, None)
891
        client_sock.sendall(bytes)
892
        client_sock.close()
893
        return server._build_protocol()
894
895
    def assertProtocolOne(self, server_protocol):
896
        # Use assertIs because assertIsInstance will wrongly pass
897
        # SmartServerRequestProtocolTwo (because it subclasses
898
        # SmartServerRequestProtocolOne).
899
        self.assertIs(
900
            type(server_protocol), protocol.SmartServerRequestProtocolOne)
901
902
    def assertProtocolTwo(self, server_protocol):
903
        self.assertIsInstance(
904
            server_protocol, protocol.SmartServerRequestProtocolTwo)
905
906
    def test_pipe_like_build_protocol_empty_bytes(self):
907
        # Any empty request (i.e. no bytes) is detected as protocol version one.
908
        server_protocol = self.build_protocol_pipe_like('')
909
        self.assertProtocolOne(server_protocol)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
910
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
911
    def test_socket_like_build_protocol_empty_bytes(self):
912
        # Any empty request (i.e. no bytes) is detected as protocol version one.
913
        server_protocol = self.build_protocol_socket('')
914
        self.assertProtocolOne(server_protocol)
915
916
    def test_pipe_like_build_protocol_non_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
917
        # A request that doesn't start with "bzr request 2\n" is version one.
918
        server_protocol = self.build_protocol_pipe_like('abc\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
919
        self.assertProtocolOne(server_protocol)
920
921
    def test_socket_build_protocol_non_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
922
        # A request that doesn't start with "bzr request 2\n" is version one.
923
        server_protocol = self.build_protocol_socket('abc\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
924
        self.assertProtocolOne(server_protocol)
925
926
    def test_pipe_like_build_protocol_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
927
        # A request that starts with "bzr request 2\n" is version two.
928
        server_protocol = self.build_protocol_pipe_like('bzr request 2\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
929
        self.assertProtocolTwo(server_protocol)
930
931
    def test_socket_build_protocol_two(self):
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
932
        # A request that starts with "bzr request 2\n" is version two.
933
        server_protocol = self.build_protocol_socket('bzr request 2\n')
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
934
        self.assertProtocolTwo(server_protocol)
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
935
936
937
class TestGetProtocolFactoryForBytes(tests.TestCase):
938
    """_get_protocol_factory_for_bytes identifies the protocol factory a server
939
    should use to decode a given request.  Any bytes not part of the version
940
    marker string (and thus part of the actual request) are returned alongside
941
    the protocol factory.
942
    """
943
944
    def test_version_three(self):
945
        result = medium._get_protocol_factory_for_bytes(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
946
            'bzr message 3 (bzr 1.6)\nextra bytes')
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
947
        protocol_factory, remainder = result
948
        self.assertEqual(
949
            protocol.build_server_protocol_three, protocol_factory)
950
        self.assertEqual('extra bytes', remainder)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
951
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
952
    def test_version_two(self):
953
        result = medium._get_protocol_factory_for_bytes(
954
            'bzr request 2\nextra bytes')
955
        protocol_factory, remainder = result
956
        self.assertEqual(
957
            protocol.SmartServerRequestProtocolTwo, protocol_factory)
958
        self.assertEqual('extra bytes', remainder)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
959
3245.4.41 by Andrew Bennetts
Add TestGetProtocolFactoryForBytes.
960
    def test_version_one(self):
961
        """Version one requests have no version markers."""
962
        result = medium._get_protocol_factory_for_bytes('anything\n')
963
        protocol_factory, remainder = result
964
        self.assertEqual(
965
            protocol.SmartServerRequestProtocolOne, protocol_factory)
966
        self.assertEqual('anything\n', remainder)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
967
2018.2.20 by Andrew Bennetts
Tidy up _serve_one_request.
968
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
969
class TestSmartTCPServer(tests.TestCase):
970
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
971
    def test_get_error_unexpected(self):
972
        """Error reported by server with no specific representation"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
973
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
974
        class FlakyTransport(object):
2376.3.3 by Robert Collins
Fix all smart_transport tests.
975
            base = 'a_url'
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
976
            def external_url(self):
977
                return self.base
5247.3.47 by Vincent Ladeuil
Use SmartTCPServer_for_testing for TestSmartTCPServer.test_get_error_unexpected.
978
            def get(self, path):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
979
                raise Exception("some random exception from inside server")
5247.3.47 by Vincent Ladeuil
Use SmartTCPServer_for_testing for TestSmartTCPServer.test_get_error_unexpected.
980
981
        class FlakyServer(test_server.SmartTCPServer_for_testing):
982
            def get_backing_transport(self, backing_transport_server):
983
                return FlakyTransport()
984
985
        smart_server = FlakyServer()
986
        smart_server.start_server()
987
        self.addCleanup(smart_server.stop_server)
988
        t = remote.RemoteTCPTransport(smart_server.get_url())
989
        self.addCleanup(t.disconnect)
990
        err = self.assertRaises(errors.UnknownErrorFromSmartServer,
991
                                t.get, 'something')
992
        self.assertContainsRe(str(err), 'some random exception')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
993
994
995
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
996
    """Tests for connection/end to end behaviour using the TCP server.
997
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
998
    All of these tests are run with a server running in another thread serving
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
999
    a MemoryTransport, and a connection to it already open.
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1000
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1001
    the server is obtained by calling self.start_server(readonly=False).
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1002
    """
1003
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1004
    def start_server(self, readonly=False, backing_transport=None):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1005
        """Setup the server.
1006
1007
        :param readonly: Create a readonly server.
1008
        """
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
1009
        # NB: Tests using this fall into two categories: tests of the server,
1010
        # tests wanting a server. The latter should be updated to use
1011
        # self.vfs_transport_factory etc.
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1012
        if backing_transport is None:
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
1013
            mem_server = memory.MemoryServer()
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1014
            mem_server.start_server()
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
1015
            self.addCleanup(mem_server.stop_server)
4634.47.10 by Andrew Bennetts
Merge bzr.dev; fix test isolation glitch.
1016
            self.permit_url(mem_server.get_url())
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1017
            self.backing_transport = transport.get_transport(
1018
                mem_server.get_url())
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1019
        else:
1020
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1021
        if readonly:
1022
            self.real_backing_transport = self.backing_transport
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1023
            self.backing_transport = transport.get_transport(
1024
                "readonly+" + self.backing_transport.abspath('.'))
5247.2.12 by Vincent Ladeuil
Ensure that all transports close their underlying connection.
1025
        self.server = server.SmartTCPServer(self.backing_transport)
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1026
        self.server.start_server('127.0.0.1', 0)
3245.4.28 by Andrew Bennetts
Remove another XXX, and include test ID in smart server thread names.
1027
        self.server.start_background_thread('-' + self.id())
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1028
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1029
        self.addCleanup(self.stop_server)
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
1030
        self.permit_url(self.server.get_url())
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1031
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1032
    def stop_server(self):
1033
        """Disconnect the client and stop the server.
1034
1035
        This must be re-entrant as some tests will call it explicitly in
1036
        addition to the normal cleanup.
1037
        """
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1038
        if getattr(self, 'transport', None):
1039
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1040
            del self.transport
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1041
        if getattr(self, 'server', None):
1042
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1043
            del self.server
1044
1045
1046
class TestServerSocketUsage(SmartTCPTests):
1047
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1048
    def test_server_start_stop(self):
1049
        """It should be safe to stop the server with no requests."""
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1050
        self.start_server()
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1051
        t = remote.RemoteTCPTransport(self.server.get_url())
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1052
        self.stop_server()
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1053
        self.assertRaises(errors.ConnectionError, t.has, '.')
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1054
1055
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
1056
        """The server should close its listening socket when it's stopped."""
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1057
        self.start_server()
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1058
        server_url = self.server.get_url()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1059
        self.transport.has('.')
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1060
        self.stop_server()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1061
        # if the listening socket has closed, we should get a BADFD error
1062
        # when connecting, rather than a hang.
5247.2.34 by Vincent Ladeuil
Merge sftp-leaks into catch-them-all resolving conflicts
1063
        t = remote.RemoteTCPTransport(server_url)
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1064
        self.assertRaises(errors.ConnectionError, t.has, '.')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1065
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1066
1067
class WritableEndToEndTests(SmartTCPTests):
1068
    """Client to server tests that require a writable transport."""
1069
1070
    def setUp(self):
1071
        super(WritableEndToEndTests, self).setUp()
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1072
        self.start_server()
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1073
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1074
    def test_start_tcp_server(self):
1075
        url = self.server.get_url()
1076
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
1077
1078
    def test_smart_transport_has(self):
1079
        """Checking for file existence over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1080
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1081
        self.backing_transport.put_bytes("foo", "contents of foo\n")
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1082
        self.assertTrue(self.transport.has("foo"))
1083
        self.assertFalse(self.transport.has("non-foo"))
1084
1085
    def test_smart_transport_get(self):
1086
        """Read back a file over smart."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1087
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1088
        self.backing_transport.put_bytes("foo", "contents\nof\nfoo\n")
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1089
        fp = self.transport.get("foo")
1090
        self.assertEqual('contents\nof\nfoo\n', fp.read())
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1091
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1092
    def test_get_error_enoent(self):
1093
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
1094
        # The path in a raised NoSuchFile exception should be the precise path
1095
        # asked for by the client. This gives meaningful and unsurprising errors
1096
        # for users.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1097
        self._captureVar('BZR_NO_SMART_VFS', None)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1098
        err = self.assertRaises(
1099
            errors.NoSuchFile, self.transport.get, 'not%20a%20file')
4294.2.9 by Robert Collins
Fixup tests broken by cleaning up the layering.
1100
        self.assertSubset([err.path], ['not%20a%20file', './not%20a%20file'])
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1101
1102
    def test_simple_clone_conn(self):
1103
        """Test that cloning reuses the same connection."""
1104
        # we create a real connection not a loopback one, but it will use the
1105
        # same server and pipes
1752.2.74 by Andrew Bennetts
Make SmartTransport.clone return the right class, and move connection sharing into clone from __init__.
1106
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1107
        self.assertIs(self.transport.get_smart_medium(),
1108
                      conn2.get_smart_medium())
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1109
1910.19.12 by Andrew Bennetts
Activate a disabled test, rename another test to be consistent with what it's testing. (Andrew Bennetts, Robert Collins)
1110
    def test__remote_path(self):
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1111
        self.assertEquals('/foo/bar',
1112
                          self.transport._remote_path('foo/bar'))
1113
1114
    def test_clone_changes_base(self):
1115
        """Cloning transport produces one with a new base location"""
1116
        conn2 = self.transport.clone('subdir')
1117
        self.assertEquals(self.transport.base + 'subdir/',
1118
                          conn2.base)
1119
1120
    def test_open_dir(self):
1121
        """Test changing directory"""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1122
        self._captureVar('BZR_NO_SMART_VFS', None)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1123
        transport = self.transport
1124
        self.backing_transport.mkdir('toffee')
1125
        self.backing_transport.mkdir('toffee/apple')
1126
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1127
        toffee_trans = transport.clone('toffee')
1128
        # Check that each transport has only the contents of its directory
1129
        # directly visible. If state was being held in the wrong object, it's
1130
        # conceivable that cloning a transport would alter the state of the
1131
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1132
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1133
        self.assertFalse(toffee_trans.has('toffee'))
1134
        self.assertFalse(transport.has('apple'))
1135
        self.assertTrue(toffee_trans.has('apple'))
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1136
1137
    def test_open_bzrdir(self):
1138
        """Open an existing bzrdir over smart transport"""
1139
        transport = self.transport
1140
        t = self.backing_transport
1141
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
1142
        result_dir = bzrdir.BzrDir.open_containing_from_transport(transport)
1143
1144
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1145
class ReadOnlyEndToEndTests(SmartTCPTests):
1146
    """Tests from the client to the server using a readonly backing transport."""
1147
1148
    def test_mkdir_error_readonly(self):
1149
        """TransportNotPossible should be preserved from the backing transport."""
2402.1.2 by Andrew Bennetts
Deal with review comments.
1150
        self._captureVar('BZR_NO_SMART_VFS', None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1151
        self.start_server(readonly=True)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1152
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1153
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1154
1155
1156
class TestServerHooks(SmartTCPTests):
1157
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1158
    def capture_server_call(self, backing_urls, public_url):
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1159
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1160
        self.hook_calls.append((backing_urls, public_url))
1161
1162
    def test_server_started_hook_memory(self):
1163
        """The server_started hook fires when the server is started."""
1164
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1165
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1166
            self.capture_server_call, None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1167
        self.start_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1168
        # at this point, the server will be starting a thread up.
1169
        # there is no indicator at the moment, so bodge it by doing a request.
1170
        self.transport.has('.')
1171
        # The default test server uses MemoryTransport and that has no external
1172
        # url:
1173
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1174
            self.hook_calls)
1175
1176
    def test_server_started_hook_file(self):
1177
        """The server_started hook fires when the server is started."""
1178
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1179
        server.SmartTCPServer.hooks.install_named_hook('server_started',
1180
            self.capture_server_call, None)
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1181
        self.start_server(backing_transport=transport.get_transport("."))
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1182
        # at this point, the server will be starting a thread up.
1183
        # there is no indicator at the moment, so bodge it by doing a request.
1184
        self.transport.has('.')
1185
        # The default test server uses MemoryTransport and that has no external
1186
        # url:
1187
        self.assertEqual([([
1188
            self.backing_transport.base, self.backing_transport.external_url()],
1189
             self.transport.base)],
1190
            self.hook_calls)
1191
1192
    def test_server_stopped_hook_simple_memory(self):
1193
        """The server_stopped hook fires when the server is stopped."""
1194
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1195
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1196
            self.capture_server_call, None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1197
        self.start_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1198
        result = [([self.backing_transport.base], self.transport.base)]
1199
        # check the stopping message isn't emitted up front.
1200
        self.assertEqual([], self.hook_calls)
1201
        # nor after a single message
1202
        self.transport.has('.')
1203
        self.assertEqual([], self.hook_calls)
1204
        # clean up the server
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1205
        self.stop_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1206
        # now it should have fired.
1207
        self.assertEqual(result, self.hook_calls)
1208
1209
    def test_server_stopped_hook_simple_file(self):
1210
        """The server_stopped hook fires when the server is stopped."""
1211
        self.hook_calls = []
3256.2.12 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in test_smart_transport.py.
1212
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
1213
            self.capture_server_call, None)
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1214
        self.start_server(backing_transport=transport.get_transport("."))
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1215
        result = [(
1216
            [self.backing_transport.base, self.backing_transport.external_url()]
1217
            , self.transport.base)]
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1218
        # check the stopping message isn't emitted up front.
1219
        self.assertEqual([], self.hook_calls)
1220
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1221
        self.transport.has('.')
1222
        self.assertEqual([], self.hook_calls)
1223
        # clean up the server
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1224
        self.stop_server()
2376.3.8 by Robert Collins
Overhaul the SmartTCPServer connect-thread logic to synchronise on startup and shutdown and notify the server if it is in accept.
1225
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1226
        self.assertEqual(result, self.hook_calls)
1227
1228
# TODO: test that when the server suffers an exception that it calls the
1229
# server-stopped hook.
1230
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1231
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1232
class SmartServerCommandTests(tests.TestCaseWithTransport):
1233
    """Tests that call directly into the command objects, bypassing the network
1234
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1235
1236
    Note: these tests are rudimentary versions of the command object tests in
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1237
    test_smart.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1238
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1239
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1240
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1241
        cmd = _mod_request.HelloRequest(None, '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1242
        response = cmd.execute()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1243
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1244
        self.assertEqual(None, response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1245
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1246
    def test_get_bundle(self):
1247
        from bzrlib.bundle import serializer
1248
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1249
        self.build_tree_contents([('hello', 'hello world')])
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1250
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1251
        rev_id = wt.commit('add hello')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1252
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1253
        cmd = _mod_request.GetBundleRequest(self.get_transport(), '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1254
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1255
        bundle = serializer.read_bundle(StringIO(response.body))
1256
        self.assertEqual((), response.args)
1257
1258
1259
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1260
    """Test that call directly into the handler logic, bypassing the network."""
1261
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1262
    def setUp(self):
1263
        super(SmartServerRequestHandlerTests, self).setUp()
2402.1.2 by Andrew Bennetts
Deal with review comments.
1264
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1265
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1266
    def build_handler(self, transport):
1267
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1268
        return _mod_request.SmartServerRequestHandler(
1269
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1270
1271
    def test_construct_request_handler(self):
1272
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1273
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1274
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1275
        self.assertFalse(handler.finished_reading)
1276
1277
    def test_hello(self):
1278
        handler = self.build_handler(None)
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1279
        handler.args_received(('hello',))
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1280
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1281
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1282
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1283
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1284
        # VFS handler classes will raise an error from "execute" if
1285
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1286
        handler = vfs.HasRequest(None, '/')
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1287
        # set environment variable after construction to make sure it's
1288
        # examined.
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1289
        # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1290
        # has called _captureVar, so it will be restored to the right state
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1291
        # afterwards.
2402.1.2 by Andrew Bennetts
Deal with review comments.
1292
        os.environ['BZR_NO_SMART_VFS'] = ''
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1293
        self.assertRaises(errors.DisabledMethod, handler.execute)
1294
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1295
    def test_readonly_exception_becomes_transport_not_possible(self):
1296
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1297
        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`.
1298
        # 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.
1299
        handler.args_received(('mkdir', 'foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1300
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1301
        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`.
1302
        # XXX: TODO: test that other TransportNotPossible errors are
1303
        # presented as TransportNotPossible - not possible to do that
1304
        # until I figure out how to trigger that relatively cleanly via
1305
        # the api. RBC 20060918
1306
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1307
    def test_hello_has_finished_body_on_dispatch(self):
1308
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1309
        handler = self.build_handler(None)
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1310
        handler.args_received(('hello',))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1311
        self.assertTrue(handler.finished_reading)
1312
        self.assertNotEqual(None, handler.response)
1313
1314
    def test_put_bytes_non_atomic(self):
1315
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1316
        handler = self.build_handler(self.get_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1317
        handler.args_received(('put_non_atomic', 'a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1318
        self.assertFalse(handler.finished_reading)
1319
        handler.accept_body('1234')
1320
        self.assertFalse(handler.finished_reading)
1321
        handler.accept_body('5678')
1322
        handler.end_of_body()
1323
        self.assertTrue(handler.finished_reading)
1324
        self.assertEqual(('ok', ), handler.response.args)
1325
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1326
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1327
    def test_readv_accept_body(self):
1328
        """'readv' should set finished_reading after reading offsets."""
1329
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1330
        handler = self.build_handler(self.get_readonly_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1331
        handler.args_received(('readv', 'a-file'))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1332
        self.assertFalse(handler.finished_reading)
1333
        handler.accept_body('2,')
1334
        self.assertFalse(handler.finished_reading)
1335
        handler.accept_body('3')
1336
        handler.end_of_body()
1337
        self.assertTrue(handler.finished_reading)
1338
        self.assertEqual(('readv', ), handler.response.args)
1339
        # co - nte - nt of a-file is the file contents we are extracting from.
1340
        self.assertEqual('nte', handler.response.body)
1341
1342
    def test_readv_short_read_response_contents(self):
1343
        """'readv' when a short read occurs sets the response appropriately."""
1344
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1345
        handler = self.build_handler(self.get_readonly_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1346
        handler.args_received(('readv', 'a-file'))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1347
        # read beyond the end of the file.
1348
        handler.accept_body('100,1')
1349
        handler.end_of_body()
1350
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1351
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1352
            handler.response.args)
1353
        self.assertEqual(None, handler.response.body)
1354
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
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)
1356
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.
1357
1358
    def test_registration(self):
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1359
        t = transport.get_transport('bzr+ssh://example.com/path')
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1360
        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.
1361
        self.assertEqual('example.com', t._host)
1362
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1363
    def test_bzr_https(self):
1364
        # https://bugs.launchpad.net/bzr/+bug/128456
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1365
        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
1366
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1367
        self.assertStartsWith(
1368
            t._http_transport.base,
1369
            'https://')
1370
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.
1371
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1372
class TestRemoteTransport(tests.TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1373
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1374
    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)
1375
        # 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.
1376
        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.
1377
        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.
1378
        client_medium = medium.SmartSimplePipesClientMedium(
1379
            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)
1380
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1381
            '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.
1382
        # 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).
1383
        client_medium._protocol_version = 1
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1384
1385
        # 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.
1386
        # method is called.  No data should have been sent, or read.
1387
        self.assertEqual(0, input.tell())
1388
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1389
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1390
        # 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.
1391
        # transport makes its own protocol instances, we check on the wire.
1392
        # XXX: TODO: give the transport a protocol factory, which can make
1393
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1394
        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.
1395
        # 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.
1396
        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.
1397
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1398
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1399
    def test__translate_error_readonly(self):
1400
        """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.
1401
        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)
1402
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1403
            'bzr://localhost/', medium=client_medium)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1404
        err = errors.ErrorFromSmartServer(("ReadOnlyError", ))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1405
        self.assertRaises(errors.TransportNotPossible,
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1406
            transport._translate_error, err)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1407
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1408
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1409
class TestSmartProtocol(tests.TestCase):
1410
    """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.
1411
1412
    Each test case gets a smart_server and smart_client created during setUp().
1413
1414
    It is planned that the client can be called with self.call_client() giving
1415
    it an expected server response, which will be fed into it when it tries to
1416
    read. Likewise, self.call_server will call a servers method with a canned
1417
    serialised client request. Output done by the client or server for these
1418
    calls will be captured to self.to_server and self.to_client. Each element
1419
    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.
1420
1421
    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.
1422
    """
1423
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1424
    request_encoder = None
1425
    response_decoder = None
1426
    server_protocol_class = None
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1427
    client_protocol_class = None
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1428
1429
    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.
1430
        """
1431
        :returns: a Request
1432
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1433
        # This is very similar to
1434
        # 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.
1435
        # XXX: make this use _SmartClient!
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1436
        if input_bytes is None:
1437
            input = StringIO()
1438
        else:
1439
            input = StringIO(input_bytes)
1440
        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.
1441
        client_medium = medium.SmartSimplePipesClientMedium(
1442
            input, output, 'base')
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1443
        request = client_medium.get_request()
1444
        if self.client_protocol_class is not None:
1445
            client_protocol = self.client_protocol_class(request)
1446
            return client_protocol, client_protocol, output
1447
        else:
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
1448
            self.assertNotEqual(None, self.request_encoder)
1449
            self.assertNotEqual(None, self.response_decoder)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1450
            requester = self.request_encoder(request)
1451
            response_handler = message.ConventionalResponseHandler()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1452
            response_protocol = self.response_decoder(
1453
                response_handler, expect_version_marker=True)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
1454
            response_handler.setProtoAndMediumRequest(
1455
                response_protocol, request)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1456
            return requester, response_handler, output
1457
1458
    def make_client_protocol(self, input_bytes=None):
1459
        result = self.make_client_protocol_and_output(input_bytes=input_bytes)
1460
        requester, response_handler, output = result
1461
        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.
1462
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1463
    def make_server_protocol(self):
1464
        out_stream = StringIO()
3245.4.34 by Andrew Bennetts
Remove another insignificant change vs. bzr.dev.
1465
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1466
        return smart_protocol, out_stream
1467
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1468
    def setUp(self):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1469
        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.
1470
        self.response_marker = getattr(
1471
            self.client_protocol_class, 'response_marker', None)
1472
        self.request_marker = getattr(
1473
            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.
1474
1475
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1476
        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.
1477
        """Check that smart (de)serialises offsets as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1478
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.
1479
        We check both serialisation and deserialisation at the same time
1480
        to ensure that the round tripping cannot skew: both directions should
1481
        be as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1482
1910.19.22 by Robert Collins
Rearrange the readv patch to put the serialise offsets method into the correct class, and document the structure of the classes somewhat better to hint to people writing patches where code should go. Also alter the test so that the client and server components are tested in one place preventing possible encoding skew from occuring.
1483
        :param expected_offsets: a readv offset list.
1484
        :param expected_seralised: an expected serial form of the offsets.
1485
        """
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
1486
        # XXX: '_deserialise_offsets' should be a method of the
1487
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1488
        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.
1489
        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.
1490
        self.assertEqual(expected_offsets, offsets)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1491
        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.
1492
        self.assertEqual(expected_serialised, serialised)
1493
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1494
    def build_protocol_waiting_for_body(self):
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1495
        smart_protocol, out_stream = self.make_server_protocol()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1496
        smart_protocol._has_dispatched = True
3245.1.14 by Andrew Bennetts
Merge from bzr.dev
1497
        smart_protocol.request = _mod_request.SmartServerRequestHandler(
1498
            None, _mod_request.request_handlers, '/')
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
1499
        class FakeCommand(_mod_request.SmartServerRequest):
1500
            def do_body(self_cmd, body_bytes):
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1501
                self.end_received = True
1502
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1503
                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.
1504
        smart_protocol.request._command = FakeCommand(None)
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1505
        # Call accept_bytes to make sure that internal state like _body_decoder
1506
        # is initialised.  This test should probably be given a clearer
1507
        # interface to work with that will not cause this inconsistency.
1508
        #   -- 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
1509
        smart_protocol.accept_bytes('')
1510
        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.
1511
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1512
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
1513
            input_tuples):
1514
        """Assert that each input_tuple serialises as expected_bytes, and the
1515
        bytes deserialise as expected_tuple.
1516
        """
1517
        # check the encoding of the server for all input_tuples matches
1518
        # expected bytes
1519
        for input_tuple in input_tuples:
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1520
            server_protocol, server_output = self.make_server_protocol()
2432.4.4 by Robert Collins
Merge hpss-protocol2.
1521
            server_protocol._send_response(
1522
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1523
            self.assertEqual(expected_bytes, server_output.getvalue())
1524
        # 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.
1525
        requester, response_handler = self.make_client_protocol(expected_bytes)
1526
        requester.call('foo')
1527
        self.assertEqual(expected_tuple, response_handler.read_response_tuple())
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1528
1529
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.
1530
class CommonSmartProtocolTestMixin(object):
1531
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1532
    def test_connection_closed_reporting(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1533
        requester, response_handler = self.make_client_protocol()
1534
        requester.call('hello')
3245.1.10 by Andrew Bennetts
Remove trailing whitespace.
1535
        ex = self.assertRaises(errors.ConnectionReset,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1536
            response_handler.read_response_tuple)
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1537
        self.assertEqual("Connection closed: "
4509.2.3 by Martin Pool
Test tweaks for ConnectionReset message change
1538
            "Unexpected end of message. Please check connectivity "
1539
            "and permissions, and report a bug if problems persist. ",
4070.8.1 by Martin Pool
Remove 'try -Dhpss' from error messages
1540
            str(ex))
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
1541
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1542
    def test_server_offset_serialisation(self):
1543
        """The Smart protocol serialises offsets as a comma and \n string.
1544
1545
        We check a number of boundary cases are as expected: empty, one offset,
1546
        one with the order of reads not increasing (an out of order read), and
1547
        one that should coalesce.
1548
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1549
        requester, response_handler = self.make_client_protocol()
1550
        self.assertOffsetSerialisation([], '', requester)
1551
        self.assertOffsetSerialisation([(1,2)], '1,2', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1552
        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.
1553
            requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1554
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1555
            '1,2\n3,4\n100,200', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
1556
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.
1557
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.
1558
class TestVersionOneFeaturesInProtocolOne(
1559
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1560
    """Tests for version one smart protocol features as implemeted by version
1561
    one."""
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1562
1563
    client_protocol_class = protocol.SmartClientRequestProtocolOne
1564
    server_protocol_class = protocol.SmartServerRequestProtocolOne
1565
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1566
    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
1567
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1568
        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
1569
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1570
        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
1571
        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.
1572
1573
    def test_construct_version_one_client_protocol(self):
1574
        # we can construct a client protocol from a client medium request
1575
        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.
1576
        client_medium = medium.SmartSimplePipesClientMedium(
1577
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1578
        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
1579
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1580
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1581
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1582
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1583
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1584
            None, out_stream.write)
1585
        smart_protocol.accept_bytes('abc')
1586
        self.assertEqual('abc', smart_protocol.in_buffer)
1587
        smart_protocol.accept_bytes('\n')
1588
        self.assertEqual(
1589
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
1590
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1591
        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
1592
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
1593
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1594
    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.
1595
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1596
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1597
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1598
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1599
        protocol.accept_bytes('defgd')
1600
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1601
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1602
        self.assertTrue(self.end_received)
1603
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1604
    def test_accept_request_and_body_all_at_once(self):
2402.1.2 by Andrew Bennetts
Deal with review comments.
1605
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
1606
        mem_transport = memory.MemoryTransport()
1607
        mem_transport.put_bytes('foo', 'abcdefghij')
1608
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1609
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
1610
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1611
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1612
        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.
1613
        self.assertEqual('readv\n3\ndefdone\n', out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1614
        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
1615
        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.
1616
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1617
    def test_accept_excess_bytes_are_preserved(self):
1618
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1619
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1620
            None, out_stream.write)
1621
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1622
        self.assertEqual("ok\x012\n", out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1623
        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
1624
        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.
1625
1626
    def test_accept_excess_bytes_after_body(self):
1627
        protocol = self.build_protocol_waiting_for_body()
1628
        protocol.accept_bytes('7\nabcdefgdone\nX')
1629
        self.assertTrue(self.end_received)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1630
        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.
1631
        self.assertEqual("", protocol.in_buffer)
1632
        protocol.accept_bytes('Y')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1633
        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.
1634
        self.assertEqual("", protocol.in_buffer)
1635
1636
    def test_accept_excess_bytes_after_dispatch(self):
1637
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1638
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1639
            None, out_stream.write)
1640
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1641
        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
1642
        smart_protocol.accept_bytes('hel')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1643
        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
1644
        smart_protocol.accept_bytes('lo\n')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1645
        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
1646
        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.
1647
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
1648
    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
1649
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1650
            None, lambda x: None)
1651
        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.
1652
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1653
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
1654
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1655
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1656
    def test__send_response_errors_with_base_response(self):
1657
        """Ensure that only the Successful/Failed subclasses are used."""
1658
        smart_protocol = protocol.SmartServerRequestProtocolOne(
1659
            None, lambda x: None)
1660
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1661
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
1662
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1663
    def test_query_version(self):
1664
        """query_version on a SmartClientProtocolOne should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1665
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1666
        The protocol provides the query_version because the domain level clients
1667
        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.
1668
        """
1669
        # What we really want to test here is that SmartClientProtocolOne calls
1670
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
4031.3.1 by Frank Aspell
Fixing various typos
1671
        # 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.
1672
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1673
        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.
1674
        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.
1675
        client_medium = medium.SmartSimplePipesClientMedium(
1676
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1677
        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
1678
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1679
        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.
1680
1681
    def test_client_call_empty_response(self):
1682
        # protocol.call() can get back an empty tuple as a response. This occurs
1683
        # when the parsed line is an empty line, and results in a tuple with
1684
        # one element - an empty string.
1685
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
1686
1687
    def test_client_call_three_element_response(self):
1688
        # protocol.call() can get back tuples of other lengths. A three element
1689
        # tuple should be unpacked as three strings.
1690
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
1691
            [('a', 'b', '34')])
1692
1693
    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.
1694
        # 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.
1695
        # wire.
1696
        expected_bytes = "foo\n7\nabcdefgdone\n"
1697
        input = StringIO("\n")
1698
        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.
1699
        client_medium = medium.SmartSimplePipesClientMedium(
1700
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1701
        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
1702
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1703
        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.
1704
        self.assertEqual(expected_bytes, output.getvalue())
1705
1706
    def test_client_call_with_body_readv_array(self):
1707
        # protocol.call_with_upload should encode the readv array and then
1708
        # length-prefix the bytes onto the wire.
1709
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
1710
        input = StringIO("\n")
1711
        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.
1712
        client_medium = medium.SmartSimplePipesClientMedium(
1713
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1714
        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
1715
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1716
        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.
1717
        self.assertEqual(expected_bytes, output.getvalue())
1718
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.
1719
    def _test_client_read_response_tuple_raises_UnknownSmartMethod(self,
1720
            server_bytes):
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1721
        input = StringIO(server_bytes)
1722
        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.
1723
        client_medium = medium.SmartSimplePipesClientMedium(
1724
            input, output, 'base')
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
1725
        request = client_medium.get_request()
1726
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1727
        smart_protocol.call('foo')
1728
        self.assertRaises(
1729
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
1730
        # The request has been finished.  There is no body to read, and
1731
        # attempts to read one will fail.
1732
        self.assertRaises(
1733
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
1734
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.
1735
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
1736
        """read_response_tuple raises UnknownSmartMethod if the response says
1737
        the server did not recognise the request.
1738
        """
1739
        server_bytes = (
1740
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
1741
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1742
            server_bytes)
1743
1744
    def test_client_read_response_tuple_raises_UnknownSmartMethod_0_11(self):
1745
        """read_response_tuple also raises UnknownSmartMethod if the response
1746
        from a bzr 0.11 says the server did not recognise the request.
1747
1748
        (bzr 0.11 sends a slightly different error message to later versions.)
1749
        """
1750
        server_bytes = (
1751
            "error\x01Generic bzr smart protocol error: bad request u'foo'\n")
1752
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
1753
            server_bytes)
1754
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
1755
    def test_client_read_body_bytes_all(self):
1756
        # read_body_bytes should decode the body bytes from the wire into
1757
        # a response.
1758
        expected_bytes = "1234567"
1759
        server_bytes = "ok\n7\n1234567done\n"
1760
        input = StringIO(server_bytes)
1761
        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.
1762
        client_medium = medium.SmartSimplePipesClientMedium(
1763
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1764
        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
1765
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1766
        smart_protocol.call('foo')
1767
        smart_protocol.read_response_tuple(True)
1768
        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.
1769
1770
    def test_client_read_body_bytes_incremental(self):
1771
        # test reading a few bytes at a time from the body
1772
        # 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.
1773
        # 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.
1774
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
1775
        # that.
1776
        expected_bytes = "1234567"
1777
        server_bytes = "ok\n7\n1234567done\n"
1778
        input = StringIO(server_bytes)
1779
        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.
1780
        client_medium = medium.SmartSimplePipesClientMedium(
1781
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1782
        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
1783
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1784
        smart_protocol.call('foo')
1785
        smart_protocol.read_response_tuple(True)
1786
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
1787
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
1788
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
1789
        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.
1790
1791
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
1792
        # cancelling the expected body needs to finish the request, but not
1793
        # read any more bytes.
1794
        expected_bytes = "1234567"
1795
        server_bytes = "ok\n7\n1234567done\n"
1796
        input = StringIO(server_bytes)
1797
        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.
1798
        client_medium = medium.SmartSimplePipesClientMedium(
1799
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1800
        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
1801
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
1802
        smart_protocol.call('foo')
1803
        smart_protocol.read_response_tuple(True)
1804
        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.
1805
        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
1806
        self.assertRaises(
1807
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1808
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
1809
    def test_client_read_body_bytes_interrupted_connection(self):
1810
        server_bytes = "ok\n999\nincomplete body"
1811
        input = StringIO(server_bytes)
1812
        output = StringIO()
1813
        client_medium = medium.SmartSimplePipesClientMedium(
1814
            input, output, 'base')
1815
        request = client_medium.get_request()
1816
        smart_protocol = self.client_protocol_class(request)
1817
        smart_protocol.call('foo')
1818
        smart_protocol.read_response_tuple(True)
1819
        self.assertRaises(
1820
            errors.ConnectionReset, smart_protocol.read_body_bytes)
1821
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
1822
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.
1823
class TestVersionOneFeaturesInProtocolTwo(
1824
    TestSmartProtocol, CommonSmartProtocolTestMixin):
1825
    """Tests for version one smart protocol features as implemeted by version
1826
    two.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1827
    """
1828
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1829
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
1830
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1831
1832
    def test_construct_version_two_server_protocol(self):
1833
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1834
        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.
1835
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1836
        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.
1837
        self.assertEqual(1, smart_protocol.next_read_size())
1838
1839
    def test_construct_version_two_client_protocol(self):
1840
        # we can construct a client protocol from a client medium request
1841
        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.
1842
        client_medium = medium.SmartSimplePipesClientMedium(
1843
            None, output, 'base')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1844
        request = client_medium.get_request()
1845
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
1846
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1847
    def test_accept_bytes_of_bad_request_to_protocol(self):
1848
        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.
1849
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1850
        smart_protocol.accept_bytes('abc')
1851
        self.assertEqual('abc', smart_protocol.in_buffer)
1852
        smart_protocol.accept_bytes('\n')
1853
        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.
1854
            self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1855
            "failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
1856
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1857
        self.assertTrue(smart_protocol._has_dispatched)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1858
        self.assertEqual(0, smart_protocol.next_read_size())
1859
1860
    def test_accept_body_bytes_to_protocol(self):
1861
        protocol = self.build_protocol_waiting_for_body()
1862
        self.assertEqual(6, protocol.next_read_size())
1863
        protocol.accept_bytes('7\nabc')
1864
        self.assertEqual(9, protocol.next_read_size())
1865
        protocol.accept_bytes('defgd')
1866
        protocol.accept_bytes('one\n')
1867
        self.assertEqual(0, protocol.next_read_size())
1868
        self.assertTrue(self.end_received)
1869
1870
    def test_accept_request_and_body_all_at_once(self):
1871
        self._captureVar('BZR_NO_SMART_VFS', None)
1872
        mem_transport = memory.MemoryTransport()
1873
        mem_transport.put_bytes('foo', 'abcdefghij')
1874
        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.
1875
        smart_protocol = self.server_protocol_class(
1876
            mem_transport, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1877
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
1878
        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.
1879
        self.assertEqual(self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1880
                         'success\nreadv\n3\ndefdone\n',
1881
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1882
        self.assertEqual('', smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1883
        self.assertEqual('', smart_protocol.in_buffer)
1884
1885
    def test_accept_excess_bytes_are_preserved(self):
1886
        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.
1887
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1888
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1889
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1890
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1891
        self.assertEqual("hello\n", smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1892
        self.assertEqual("", smart_protocol.in_buffer)
1893
1894
    def test_accept_excess_bytes_after_body(self):
1895
        # The excess bytes look like the start of another request.
1896
        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.
1897
        server_protocol.accept_bytes('7\nabcdefgdone\n' + self.response_marker)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1898
        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.
1899
        self.assertEqual(self.response_marker,
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1900
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1901
        self.assertEqual("", server_protocol.in_buffer)
1902
        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.
1903
        self.assertEqual(self.response_marker + "Y",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1904
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1905
        self.assertEqual("", server_protocol.in_buffer)
1906
1907
    def test_accept_excess_bytes_after_dispatch(self):
1908
        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.
1909
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1910
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1911
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1912
                         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.
1913
        smart_protocol.accept_bytes(self.request_marker + 'hel')
1914
        self.assertEqual(self.request_marker + "hel",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1915
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1916
        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.
1917
        self.assertEqual(self.request_marker + "hello\n",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
1918
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1919
        self.assertEqual("", smart_protocol.in_buffer)
1920
1921
    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.
1922
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1923
        self.assertEqual(1, smart_protocol.next_read_size())
1924
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1925
            _mod_request.SuccessfulSmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1926
        self.assertEqual(0, smart_protocol.next_read_size())
1927
1928
    def test__send_response_errors_with_base_response(self):
1929
        """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.
1930
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1931
        self.assertRaises(AttributeError, smart_protocol._send_response,
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
1932
            _mod_request.SmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1933
1934
    def test_query_version(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
1935
        """query_version on a SmartClientProtocolTwo should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1936
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1937
        The protocol provides the query_version because the domain level clients
1938
        may all need to be able to probe for capabilities.
1939
        """
1940
        # What we really want to test here is that SmartClientProtocolTwo calls
1941
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
4031.3.1 by Frank Aspell
Fixing various typos
1942
        # response of tuple-encoded (ok, 1).  Also, separately we should test
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1943
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1944
        input = StringIO(self.response_marker + 'success\nok\x012\n')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1945
        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.
1946
        client_medium = medium.SmartSimplePipesClientMedium(
1947
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1948
        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.
1949
        smart_protocol = self.client_protocol_class(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1950
        self.assertEqual(2, smart_protocol.query_version())
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1951
1952
    def test_client_call_empty_response(self):
1953
        # protocol.call() can get back an empty tuple as a response. This occurs
1954
        # when the parsed line is an empty line, and results in a tuple with
1955
        # one element - an empty string.
1956
        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.
1957
            self.response_marker + 'success\n\n', ('', ), [(), ('', )])
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1958
1959
    def test_client_call_three_element_response(self):
1960
        # protocol.call() can get back tuples of other lengths. A three element
1961
        # tuple should be unpacked as three strings.
1962
        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.
1963
            self.response_marker + 'success\na\x01b\x0134\n',
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1964
            ('a', 'b', '34'),
1965
            [('a', 'b', '34')])
1966
1967
    def test_client_call_with_body_bytes_uploads(self):
1968
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
1969
        # 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.
1970
        expected_bytes = self.request_marker + "foo\n7\nabcdefgdone\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1971
        input = StringIO("\n")
1972
        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.
1973
        client_medium = medium.SmartSimplePipesClientMedium(
1974
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1975
        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.
1976
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1977
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
1978
        self.assertEqual(expected_bytes, output.getvalue())
1979
1980
    def test_client_call_with_body_readv_array(self):
1981
        # protocol.call_with_upload should encode the readv array and then
1982
        # 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.
1983
        expected_bytes = self.request_marker + "foo\n7\n1,2\n5,6done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1984
        input = StringIO("\n")
1985
        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.
1986
        client_medium = medium.SmartSimplePipesClientMedium(
1987
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1988
        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.
1989
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1990
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
1991
        self.assertEqual(expected_bytes, output.getvalue())
1992
1993
    def test_client_read_body_bytes_all(self):
1994
        # read_body_bytes should decode the body bytes from the wire into
1995
        # a response.
1996
        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.
1997
        server_bytes = (self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
1998
                        "success\nok\n7\n1234567done\n")
1999
        input = StringIO(server_bytes)
2000
        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.
2001
        client_medium = medium.SmartSimplePipesClientMedium(
2002
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2003
        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.
2004
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2005
        smart_protocol.call('foo')
2006
        smart_protocol.read_response_tuple(True)
2007
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
2008
2009
    def test_client_read_body_bytes_incremental(self):
2010
        # test reading a few bytes at a time from the body
2011
        # XXX: possibly we should test dribbling the bytes into the stringio
2012
        # to make the state machine work harder: however, as we use the
2013
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
2014
        # that.
2015
        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.
2016
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2017
        input = StringIO(server_bytes)
2018
        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.
2019
        client_medium = medium.SmartSimplePipesClientMedium(
2020
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2021
        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.
2022
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2023
        smart_protocol.call('foo')
2024
        smart_protocol.read_response_tuple(True)
2025
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2026
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2027
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2028
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2029
2030
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2031
        # cancelling the expected body needs to finish the request, but not
2032
        # 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.
2033
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2034
        input = StringIO(server_bytes)
2035
        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.
2036
        client_medium = medium.SmartSimplePipesClientMedium(
2037
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2038
        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.
2039
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2040
        smart_protocol.call('foo')
2041
        smart_protocol.read_response_tuple(True)
2042
        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.
2043
        self.assertEqual(len(self.response_marker + 'success\nok\n'),
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2044
                         input.tell())
2045
        self.assertRaises(
2046
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2047
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2048
    def test_client_read_body_bytes_interrupted_connection(self):
2049
        server_bytes = (self.response_marker +
2050
                        "success\nok\n999\nincomplete body")
2051
        input = StringIO(server_bytes)
2052
        output = StringIO()
2053
        client_medium = medium.SmartSimplePipesClientMedium(
2054
            input, output, 'base')
2055
        request = client_medium.get_request()
2056
        smart_protocol = self.client_protocol_class(request)
2057
        smart_protocol.call('foo')
2058
        smart_protocol.read_response_tuple(True)
2059
        self.assertRaises(
2060
            errors.ConnectionReset, smart_protocol.read_body_bytes)
2061
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2062
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.
2063
class TestSmartProtocolTwoSpecificsMixin(object):
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2064
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2065
    def assertBodyStreamSerialisation(self, expected_serialisation,
2066
                                      body_stream):
2067
        """Assert that body_stream is serialised as expected_serialisation."""
2068
        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.
2069
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
2070
        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.
2071
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.
2072
    def assertBodyStreamRoundTrips(self, body_stream):
2073
        """Assert that body_stream is the same after being serialised and
2074
        deserialised.
2075
        """
2076
        out_stream = StringIO()
2077
        protocol._send_stream(body_stream, out_stream.write)
2078
        decoder = protocol.ChunkedBodyDecoder()
2079
        decoder.accept_bytes(out_stream.getvalue())
2080
        decoded_stream = list(iter(decoder.read_next_chunk, None))
2081
        self.assertEqual(body_stream, decoded_stream)
2082
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2083
    def test_body_stream_serialisation_empty(self):
2084
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2085
        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.
2086
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2087
2088
    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.
2089
        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.
2090
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2091
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
2092
            '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.
2093
            stream)
2094
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2095
2096
    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.
2097
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2098
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2099
        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.
2100
        """
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
2101
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2102
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2103
            '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.
2104
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2105
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2106
    def test_body_stream_error_serialistion(self):
2107
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2108
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2109
                      ('FailureName', 'failure arg'))]
2110
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2111
            '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.
2112
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
2113
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2114
        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.
2115
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2116
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2117
    def test__send_response_includes_failure_marker(self):
2118
        """FailedSmartServerResponse have 'failed\n' after the version."""
2119
        out_stream = StringIO()
2120
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2121
            None, out_stream.write)
2122
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2123
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2124
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
2125
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2126
2127
    def test__send_response_includes_success_marker(self):
2128
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
2129
        out_stream = StringIO()
2130
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2131
            None, out_stream.write)
2132
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2133
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2134
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
2135
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2136
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2137
    def test__send_response_with_body_stream_sets_finished_reading(self):
2138
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2139
            None, lambda x: None)
2140
        self.assertEqual(1, smart_protocol.next_read_size())
2141
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2142
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2143
        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.
2144
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2145
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2146
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2147
        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.
2148
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2149
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2150
                        "success\nok\n" + body_header + two_body_chunks +
2151
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2152
        input = StringIO(server_bytes)
2153
        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.
2154
        client_medium = medium.SmartSimplePipesClientMedium(
2155
            input, output, 'base')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2156
        request = client_medium.get_request()
2157
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2158
        smart_protocol.call('foo')
2159
        smart_protocol.read_response_tuple(True)
2160
        stream = smart_protocol.read_streamed_body()
2161
        self.assertEqual(['1234', '567'], list(stream))
2162
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2163
    def test_read_streamed_body_error(self):
2164
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2165
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2166
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2167
        err_signal = 'ERR\n'
2168
        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.
2169
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2170
        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.
2171
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2172
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2173
        input = StringIO(server_bytes)
2174
        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.
2175
        client_medium = medium.SmartSimplePipesClientMedium(
2176
            input, output, 'base')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2177
        smart_request = client_medium.get_request()
2178
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2179
        smart_protocol.call('foo')
2180
        smart_protocol.read_response_tuple(True)
2181
        expected_chunks = [
2182
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2183
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2184
        stream = smart_protocol.read_streamed_body()
2185
        self.assertEqual(expected_chunks, list(stream))
2186
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2187
    def test_streamed_body_bytes_interrupted_connection(self):
2188
        body_header = 'chunked\n'
2189
        incomplete_body_chunk = "9999\nincomplete chunk"
2190
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2191
                        "success\nok\n" + body_header + incomplete_body_chunk)
2192
        input = StringIO(server_bytes)
2193
        output = StringIO()
2194
        client_medium = medium.SmartSimplePipesClientMedium(
2195
            input, output, 'base')
2196
        request = client_medium.get_request()
2197
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2198
        smart_protocol.call('foo')
2199
        smart_protocol.read_response_tuple(True)
2200
        stream = smart_protocol.read_streamed_body()
2201
        self.assertRaises(errors.ConnectionReset, stream.next)
2202
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2203
    def test_client_read_response_tuple_sets_response_status(self):
2204
        server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
2205
        input = StringIO(server_bytes)
2206
        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.
2207
        client_medium = medium.SmartSimplePipesClientMedium(
2208
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2209
        request = client_medium.get_request()
2210
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2211
        smart_protocol.call('foo')
2212
        smart_protocol.read_response_tuple(False)
2213
        self.assertEqual(True, smart_protocol.response_status)
2214
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2215
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2216
        """read_response_tuple raises UnknownSmartMethod if the response says
2217
        the server did not recognise the request.
2218
        """
2219
        server_bytes = (
2220
            protocol.RESPONSE_VERSION_TWO +
2221
            "failed\n" +
2222
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2223
        input = StringIO(server_bytes)
2224
        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.
2225
        client_medium = medium.SmartSimplePipesClientMedium(
2226
            input, output, 'base')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2227
        request = client_medium.get_request()
2228
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2229
        smart_protocol.call('foo')
2230
        self.assertRaises(
2231
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2232
        # The request has been finished.  There is no body to read, and
2233
        # attempts to read one will fail.
2234
        self.assertRaises(
2235
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2236
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2237
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.
2238
class TestSmartProtocolTwoSpecifics(
2239
        TestSmartProtocol, TestSmartProtocolTwoSpecificsMixin):
2240
    """Tests for aspects of smart protocol version two that are unique to
2241
    version two.
2242
2243
    Thus tests involving body streams and success/failure markers belong here.
2244
    """
2245
2246
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
2247
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2248
2249
2250
class TestVersionOneFeaturesInProtocolThree(
2251
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2252
    """Tests for version one smart protocol features as implemented by version
2253
    three.
2254
    """
2255
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2256
    request_encoder = protocol.ProtocolThreeRequester
2257
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2258
    # build_server_protocol_three is a function, so we can't set it as a class
2259
    # 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.
2260
    # method.  So we make server_protocol_class be a static method, rather than
2261
    # simply doing:
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2262
    # "server_protocol_class = protocol.build_server_protocol_three".
3245.4.10 by Andrew Bennetts
Use a less ugly hack for TestVersionOneFeaturesInProtocolThree.server_protocol_class.
2263
    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.
2264
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2265
    def setUp(self):
2266
        super(TestVersionOneFeaturesInProtocolThree, self).setUp()
2267
        self.response_marker = protocol.MESSAGE_VERSION_THREE
2268
        self.request_marker = protocol.MESSAGE_VERSION_THREE
2269
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2270
    def test_construct_version_three_server_protocol(self):
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2271
        smart_protocol = protocol.ProtocolThreeDecoder(None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2272
        self.assertEqual('', smart_protocol.unused_data)
3649.5.5 by John Arbash Meinel
Fix the test suite.
2273
        self.assertEqual([], smart_protocol._in_buffer_list)
2274
        self.assertEqual(0, smart_protocol._in_buffer_len)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2275
        self.assertFalse(smart_protocol._has_dispatched)
3195.3.19 by Andrew Bennetts
Remove a stray pdb, fix a test.
2276
        # The protocol starts by expecting four bytes, a length prefix for the
2277
        # headers.
2278
        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.
2279
2280
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2281
class LoggingMessageHandler(object):
2282
2283
    def __init__(self):
2284
        self.event_log = []
2285
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2286
    def _log(self, *args):
2287
        self.event_log.append(args)
2288
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2289
    def headers_received(self, headers):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2290
        self._log('headers', headers)
2291
2292
    def protocol_error(self, exception):
2293
        self._log('protocol_error', exception)
2294
2295
    def byte_part_received(self, byte):
2296
        self._log('byte', byte)
2297
2298
    def bytes_part_received(self, bytes):
2299
        self._log('bytes', bytes)
2300
2301
    def structure_part_received(self, structure):
2302
        self._log('structure', structure)
2303
2304
    def end_received(self):
2305
        self._log('end')
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2306
2307
2308
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.
2309
    """Tests for v3 of the server-side protocol."""
2310
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2311
    request_encoder = protocol.ProtocolThreeRequester
2312
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2313
    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.
2314
2315
    def test_trivial_request(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2316
        """Smoke test for the simplest possible v3 request: empty headers, no
2317
        message parts.
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2318
        """
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2319
        output = StringIO()
2320
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2321
        end = 'e'
2322
        request_bytes = headers + end
2323
        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.
2324
        smart_protocol.accept_bytes(request_bytes)
2325
        self.assertEqual(0, smart_protocol.next_read_size())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2326
        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.
2327
4515.1.1 by Andrew Bennetts
Fix bug in HPSS v3 decoder when receiving multiple lots of excess bytes.
2328
    def test_repeated_excess(self):
2329
        """Repeated calls to accept_bytes after the message end has been parsed
2330
        accumlates the bytes in the unused_data attribute.
2331
        """
2332
        output = StringIO()
2333
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2334
        end = 'e'
2335
        request_bytes = headers + end
2336
        smart_protocol = self.server_protocol_class(LoggingMessageHandler())
2337
        smart_protocol.accept_bytes(request_bytes)
2338
        self.assertEqual('', smart_protocol.unused_data)
2339
        smart_protocol.accept_bytes('aaa')
2340
        self.assertEqual('aaa', smart_protocol.unused_data)
2341
        smart_protocol.accept_bytes('bbb')
2342
        self.assertEqual('aaabbb', smart_protocol.unused_data)
2343
        self.assertEqual(0, smart_protocol.next_read_size())
2344
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2345
    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.
2346
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2347
        message_handler = LoggingMessageHandler()
2348
        smart_protocol = self.server_protocol_class(message_handler)
2349
        smart_protocol.accept_bytes(headers)
2350
        # Clear the event log
2351
        del message_handler.event_log[:]
2352
        return smart_protocol, message_handler.event_log
2353
2354
    def test_decode_one_byte(self):
2355
        """The protocol can decode a 'one byte' message part."""
2356
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2357
        smart_protocol.accept_bytes('ox')
2358
        self.assertEqual([('byte', 'x')], event_log)
2359
2360
    def test_decode_bytes(self):
2361
        """The protocol can decode a 'bytes' message part."""
2362
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2363
        smart_protocol.accept_bytes(
2364
            'b' # message part kind
2365
            '\0\0\0\x07' # length prefix
2366
            'payload' # payload
2367
            )
2368
        self.assertEqual([('bytes', 'payload')], event_log)
2369
2370
    def test_decode_structure(self):
2371
        """The protocol can decode a 'structure' message part."""
2372
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2373
        smart_protocol.accept_bytes(
2374
            's' # message part kind
2375
            '\0\0\0\x07' # length prefix
2376
            'l3:ARGe' # ['ARG']
2377
            )
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
2378
        self.assertEqual([('structure', ('ARG',))], event_log)
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2379
2380
    def test_decode_multiple_bytes(self):
2381
        """The protocol can decode a multiple 'bytes' message parts."""
2382
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2383
        smart_protocol.accept_bytes(
2384
            'b' # message part kind
2385
            '\0\0\0\x05' # length prefix
2386
            'first' # payload
2387
            'b' # message part kind
2388
            '\0\0\0\x06'
2389
            'second'
2390
            )
2391
        self.assertEqual(
2392
            [('bytes', 'first'), ('bytes', 'second')], event_log)
2393
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.
2394
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2395
class TestConventionalResponseHandlerBodyStream(tests.TestCase):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2396
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2397
    def make_response_handler(self, response_bytes):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2398
        from bzrlib.smart.message import ConventionalResponseHandler
2399
        response_handler = ConventionalResponseHandler()
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2400
        protocol_decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2401
        # put decoder in desired state (waiting for message parts)
2402
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2403
        output = StringIO()
2404
        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.
2405
            StringIO(response_bytes), output, 'base')
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2406
        medium_request = client_medium.get_request()
2407
        medium_request.finished_writing()
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2408
        response_handler.setProtoAndMediumRequest(
2409
            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.
2410
        return response_handler
2411
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2412
    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.
2413
        response_handler = self.make_response_handler(interrupted_body_stream)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2414
        stream = response_handler.read_streamed_body()
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2415
        self.assertEqual('aaa', stream.next())
2416
        self.assertEqual('bbb', stream.next())
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2417
        exc = self.assertRaises(errors.ErrorFromSmartServer, stream.next)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2418
        self.assertEqual(('error', 'Boom!'), exc.error_tuple)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2419
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2420
    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.
2421
        interrupted_body_stream = (
2422
            'oS' # successful response
2423
            's\0\0\0\x02le' # empty args
2424
            'b\0\0\xff\xffincomplete chunk')
2425
        response_handler = self.make_response_handler(interrupted_body_stream)
2426
        stream = response_handler.read_streamed_body()
2427
        self.assertRaises(errors.ConnectionReset, stream.next)
2428
2429
    def test_read_body_bytes_interrupted_by_connection_lost(self):
2430
        interrupted_body_stream = (
2431
            'oS' # successful response
2432
            's\0\0\0\x02le' # empty args
2433
            'b\0\0\xff\xffincomplete chunk')
2434
        response_handler = self.make_response_handler(interrupted_body_stream)
2435
        self.assertRaises(
2436
            errors.ConnectionReset, response_handler.read_body_bytes)
2437
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2438
    def test_multiple_bytes_parts(self):
2439
        multiple_bytes_parts = (
2440
            'oS' # successful response
2441
            's\0\0\0\x02le' # empty args
2442
            'b\0\0\0\x0bSome bytes\n' # some bytes
2443
            'b\0\0\0\x0aMore bytes' # more bytes
2444
            'e' # message end
2445
            )
2446
        response_handler = self.make_response_handler(multiple_bytes_parts)
2447
        self.assertEqual(
2448
            'Some bytes\nMore bytes', response_handler.read_body_bytes())
2449
        response_handler = self.make_response_handler(multiple_bytes_parts)
2450
        self.assertEqual(
2451
            ['Some bytes\n', 'More bytes'],
2452
            list(response_handler.read_streamed_body()))
2453
2454
3923.5.6 by Andrew Bennetts
Fix a style nit.
2455
class FakeResponder(object):
2456
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2457
    response_sent = False
3923.5.6 by Andrew Bennetts
Fix a style nit.
2458
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2459
    def send_error(self, exc):
2460
        raise exc
3923.5.6 by Andrew Bennetts
Fix a style nit.
2461
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2462
    def send_response(self, response):
2463
        pass
2464
2465
2466
class TestConventionalRequestHandlerBodyStream(tests.TestCase):
2467
    """Tests for ConventionalRequestHandler's handling of request bodies."""
2468
2469
    def make_request_handler(self, request_bytes):
2470
        """Make a ConventionalRequestHandler for the given bytes using test
2471
        doubles for the request_handler and the responder.
2472
        """
2473
        from bzrlib.smart.message import ConventionalRequestHandler
2474
        request_handler = InstrumentedRequestHandler()
2475
        request_handler.response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
3923.5.6 by Andrew Bennetts
Fix a style nit.
2476
        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.
2477
        message_handler = ConventionalRequestHandler(request_handler, responder)
2478
        protocol_decoder = protocol.ProtocolThreeDecoder(message_handler)
2479
        # put decoder in desired state (waiting for message parts)
2480
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2481
        protocol_decoder.accept_bytes(request_bytes)
2482
        return request_handler
2483
2484
    def test_multiple_bytes_parts(self):
2485
        """Each bytes part triggers a call to the request_handler's
2486
        accept_body method.
2487
        """
2488
        multiple_bytes_parts = (
2489
            's\0\0\0\x07l3:fooe' # args
2490
            'b\0\0\0\x0bSome bytes\n' # some bytes
2491
            'b\0\0\0\x0aMore bytes' # more bytes
2492
            'e' # message end
2493
            )
2494
        request_handler = self.make_request_handler(multiple_bytes_parts)
2495
        accept_body_calls = [
2496
            call_info[1] for call_info in request_handler.calls
2497
            if call_info[0] == 'accept_body']
2498
        self.assertEqual(
2499
            ['Some bytes\n', 'More bytes'], accept_body_calls)
2500
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
2501
    def test_error_flag_after_body(self):
2502
        body_then_error = (
2503
            's\0\0\0\x07l3:fooe' # request args
2504
            'b\0\0\0\x0bSome bytes\n' # some bytes
2505
            'b\0\0\0\x0aMore bytes' # more bytes
2506
            'oE' # error flag
2507
            's\0\0\0\x07l3:bare' # error args
2508
            'e' # message end
2509
            )
2510
        request_handler = self.make_request_handler(body_then_error)
2511
        self.assertEqual(
2512
            [('post_body_error_received', ('bar',)), ('end_received',)],
2513
            request_handler.calls[-2:])
2514
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2515
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.
2516
class TestMessageHandlerErrors(tests.TestCase):
2517
    """Tests for v3 that unrecognised (but well-formed) requests/responses are
2518
    still fully read off the wire, so that subsequent requests/responses on the
2519
    same medium can be decoded.
2520
    """
2521
2522
    def test_non_conventional_request(self):
2523
        """ConventionalRequestHandler (the default message handler on the
2524
        server side) will reject an unconventional message, but still consume
2525
        all the bytes of that message and signal when it has done so.
2526
2527
        This is what allows a server to continue to accept requests after the
2528
        client sends a completely unrecognised request.
2529
        """
2530
        # Define an invalid request (but one that is a well-formed message).
2531
        # This particular invalid request not only lacks the mandatory
2532
        # verb+args tuple, it has a single-byte part, which is forbidden.  In
2533
        # fact it has that part twice, to trigger multiple errors.
2534
        invalid_request = (
2535
            protocol.MESSAGE_VERSION_THREE +  # protocol version marker
2536
            '\0\0\0\x02de' + # empty headers
2537
            'oX' + # a single byte part: 'X'.  ConventionalRequestHandler will
2538
                   # error at this part.
2539
            'oX' + # and again.
2540
            'e' # end of message
2541
            )
2542
2543
        to_server = StringIO(invalid_request)
2544
        from_server = StringIO()
2545
        transport = memory.MemoryTransport('memory:///')
2546
        server = medium.SmartServerPipeStreamMedium(
2547
            to_server, from_server, transport)
2548
        proto = server._build_protocol()
2549
        message_handler = proto.message_handler
2550
        server._serve_one_request(proto)
2551
        # All the bytes have been read from the medium...
2552
        self.assertEqual('', to_server.read())
2553
        # ...and the protocol decoder has consumed all the bytes, and has
2554
        # finished reading.
2555
        self.assertEqual('', proto.unused_data)
2556
        self.assertEqual(0, proto.next_read_size())
2557
2558
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.
2559
class InstrumentedRequestHandler(object):
2560
    """Test Double of SmartServerRequestHandler."""
2561
2562
    def __init__(self):
2563
        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.
2564
        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.
2565
2566
    def no_body_received(self):
2567
        self.calls.append(('no_body_received',))
2568
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).
2569
    def end_received(self):
2570
        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.
2571
        self.finished_reading = True
2572
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
2573
    def args_received(self, args):
2574
        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.
2575
2576
    def accept_body(self, bytes):
2577
        self.calls.append(('accept_body', bytes))
2578
2579
    def end_of_body(self):
2580
        self.calls.append(('end_of_body',))
2581
        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).
2582
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
2583
    def post_body_error_received(self, error_args):
2584
        self.calls.append(('post_body_error_received', error_args))
2585
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.
2586
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2587
class StubRequest(object):
2588
2589
    def finished_reading(self):
2590
        pass
2591
2592
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2593
class TestClientDecodingProtocolThree(TestSmartProtocol):
2594
    """Tests for v3 of the client-side protocol decoding."""
2595
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2596
    def make_logging_response_decoder(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2597
        """Make v3 response decoder using a test response handler."""
2598
        response_handler = LoggingMessageHandler()
2599
        decoder = protocol.ProtocolThreeDecoder(response_handler)
2600
        return decoder, response_handler
2601
2602
    def make_conventional_response_decoder(self):
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2603
        """Make v3 response decoder using a conventional response handler."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2604
        response_handler = message.ConventionalResponseHandler()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2605
        decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2606
        response_handler.setProtoAndMediumRequest(decoder, StubRequest())
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2607
        return decoder, response_handler
2608
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2609
    def test_trivial_response_decoding(self):
2610
        """Smoke test for the simplest possible v3 response: empty headers,
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2611
        status byte, empty args, no body.
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2612
        """
2613
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2614
        response_status = 'oS' # success
2615
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2616
        end = 'e' # end marker
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2617
        message_bytes = headers + response_status + args + end
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2618
        decoder, response_handler = self.make_logging_response_decoder()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2619
        decoder.accept_bytes(message_bytes)
2620
        # The protocol decoder has finished, and consumed all bytes
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
2621
        self.assertEqual(0, decoder.next_read_size())
2622
        self.assertEqual('', decoder.unused_data)
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2623
        # The message handler has been invoked with all the parts of the
2624
        # trivial response: empty headers, status byte, no args, end.
2625
        self.assertEqual(
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
2626
            [('headers', {}), ('byte', 'S'), ('structure', ()), ('end',)],
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
2627
            response_handler.event_log)
3195.3.5 by Andrew Bennetts
Start writing the client-side protocol logic for HPSS v3.
2628
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2629
    def test_incomplete_message(self):
2630
        """A decoder will keep signalling that it needs more bytes via
2631
        next_read_size() != 0 until it has seen a complete message, regardless
2632
        which state it is in.
2633
        """
2634
        # Define a simple response that uses all possible message parts.
2635
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2636
        response_status = 'oS' # success
2637
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
2638
        body = 'b\0\0\0\x04BODY' # a body: 'BODY'
2639
        end = 'e' # end marker
2640
        simple_response = headers + response_status + args + body + end
2641
        # Feed the request to the decoder one byte at a time.
2642
        decoder, response_handler = self.make_logging_response_decoder()
2643
        for byte in simple_response:
2644
            self.assertNotEqual(0, decoder.next_read_size())
2645
            decoder.accept_bytes(byte)
2646
        # Now the response is complete
2647
        self.assertEqual(0, decoder.next_read_size())
2648
2649
    def test_read_response_tuple_raises_UnknownSmartMethod(self):
2650
        """read_response_tuple raises UnknownSmartMethod if the server replied
2651
        with 'UnknownMethod'.
2652
        """
3245.4.35 by Andrew Bennetts
Remove some commented out cruft, test (and fix) handling of an 'UnknownMethod' response.
2653
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2654
        response_status = 'oE' # error flag
2655
        # args: ('UnknownMethod', 'method-name')
2656
        args = 's\0\0\0\x20l13:UnknownMethod11:method-namee'
2657
        end = 'e' # end marker
2658
        message_bytes = headers + response_status + args + end
2659
        decoder, response_handler = self.make_conventional_response_decoder()
2660
        decoder.accept_bytes(message_bytes)
2661
        error = self.assertRaises(
2662
            errors.UnknownSmartMethod, response_handler.read_response_tuple)
2663
        self.assertEqual('method-name', error.verb)
2664
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2665
    def test_read_response_tuple_error(self):
2666
        """If the response has an error, it is raised as an exception."""
2667
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2668
        response_status = 'oE' # error
2669
        args = 's\0\0\0\x1al9:first arg10:second arge' # two args
2670
        end = 'e' # end marker
2671
        message_bytes = headers + response_status + args + end
2672
        decoder, response_handler = self.make_conventional_response_decoder()
2673
        decoder.accept_bytes(message_bytes)
2674
        error = self.assertRaises(
2675
            errors.ErrorFromSmartServer, response_handler.read_response_tuple)
2676
        self.assertEqual(('first arg', 'second arg'), error.error_tuple)
2677
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.
2678
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2679
class TestClientEncodingProtocolThree(TestSmartProtocol):
2680
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2681
    request_encoder = protocol.ProtocolThreeRequester
2682
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2683
    server_protocol_class = protocol.ProtocolThreeDecoder
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2684
2685
    def make_client_encoder_and_output(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2686
        result = self.make_client_protocol_and_output()
2687
        requester, response_handler, output = result
2688
        return requester, output
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2689
2690
    def test_call_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2691
        """A smoke test for ProtocolThreeRequester.call.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2692
2693
        This test checks that a particular simple invocation of call emits the
2694
        correct bytes for that invocation.
2695
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2696
        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.
2697
        requester.set_headers({'header name': 'header value'})
2698
        requester.call('one arg')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2699
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2700
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2701
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2702
            's\x00\x00\x00\x0bl7:one arge' # args
2703
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2704
            output.getvalue())
2705
2706
    def test_call_with_body_bytes_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2707
        """A smoke test for ProtocolThreeRequester.call_with_body_bytes.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2708
2709
        This test checks that a particular simple invocation of
2710
        call_with_body_bytes emits the correct bytes for that invocation.
2711
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2712
        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.
2713
        requester.set_headers({'header name': 'header value'})
2714
        requester.call_with_body_bytes(('one arg',), 'body bytes')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2715
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
2716
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2717
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2718
            's\x00\x00\x00\x0bl7:one arge' # args
2719
            'b' # there is a prefixed body
2720
            '\x00\x00\x00\nbody bytes' # the prefixed body
2721
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2722
            output.getvalue())
2723
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.
2724
    def test_call_writes_just_once(self):
2725
        """A bodyless request is written to the medium all at once."""
2726
        medium_request = StubMediumRequest()
2727
        encoder = protocol.ProtocolThreeRequester(medium_request)
2728
        encoder.call('arg1', 'arg2', 'arg3')
2729
        self.assertEqual(
2730
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2731
2732
    def test_call_with_body_bytes_writes_just_once(self):
2733
        """A request with body bytes is written to the medium all at once."""
2734
        medium_request = StubMediumRequest()
2735
        encoder = protocol.ProtocolThreeRequester(medium_request)
2736
        encoder.call_with_body_bytes(('arg', 'arg'), 'body bytes')
2737
        self.assertEqual(
2738
            ['accept_bytes', 'finished_writing'], medium_request.calls)
2739
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2740
    def test_call_with_body_stream_smoke_test(self):
2741
        """A smoke test for ProtocolThreeRequester.call_with_body_stream.
2742
2743
        This test checks that a particular simple invocation of
2744
        call_with_body_stream emits the correct bytes for that invocation.
2745
        """
2746
        requester, output = self.make_client_encoder_and_output()
2747
        requester.set_headers({'header name': 'header value'})
2748
        stream = ['chunk 1', 'chunk two']
2749
        requester.call_with_body_stream(('one arg',), stream)
2750
        self.assertEquals(
2751
            'bzr message 3 (bzr 1.6)\n' # protocol version
2752
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
2753
            's\x00\x00\x00\x0bl7:one arge' # args
2754
            'b\x00\x00\x00\x07chunk 1' # a prefixed body chunk
2755
            'b\x00\x00\x00\x09chunk two' # a prefixed body chunk
2756
            'e', # end
2757
            output.getvalue())
2758
2759
    def test_call_with_body_stream_empty_stream(self):
2760
        """call_with_body_stream with an empty stream."""
2761
        requester, output = self.make_client_encoder_and_output()
2762
        requester.set_headers({})
2763
        stream = []
2764
        requester.call_with_body_stream(('one arg',), stream)
2765
        self.assertEquals(
2766
            'bzr message 3 (bzr 1.6)\n' # protocol version
2767
            '\x00\x00\x00\x02de' # headers
2768
            's\x00\x00\x00\x0bl7:one arge' # args
2769
            # no body chunks
2770
            'e', # end
2771
            output.getvalue())
2772
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2773
    def test_call_with_body_stream_error(self):
2774
        """call_with_body_stream will abort the streamed body with an
2775
        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.
2776
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2777
        The resulting request will still be a complete message.
2778
        """
2779
        requester, output = self.make_client_encoder_and_output()
2780
        requester.set_headers({})
2781
        def stream_that_fails():
2782
            yield 'aaa'
2783
            yield 'bbb'
2784
            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.
2785
        self.assertRaises(Exception, requester.call_with_body_stream,
2786
            ('one arg',), stream_that_fails())
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
2787
        self.assertEquals(
2788
            'bzr message 3 (bzr 1.6)\n' # protocol version
2789
            '\x00\x00\x00\x02de' # headers
2790
            's\x00\x00\x00\x0bl7:one arge' # args
2791
            'b\x00\x00\x00\x03aaa' # body
2792
            'b\x00\x00\x00\x03bbb' # more body
2793
            'oE' # error flag
2794
            's\x00\x00\x00\x09l5:errore' # error args: ('error',)
2795
            'e', # end
2796
            output.getvalue())
2797
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.
2798
2799
class StubMediumRequest(object):
2800
    """A stub medium request that tracks the number of times accept_bytes is
2801
    called.
2802
    """
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2803
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.
2804
    def __init__(self):
2805
        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.
2806
        self._medium = 'dummy medium'
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2807
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
2808
    def accept_bytes(self, bytes):
2809
        self.calls.append('accept_bytes')
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
2810
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.
2811
    def finished_writing(self):
2812
        self.calls.append('finished_writing')
2813
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
2814
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2815
interrupted_body_stream = (
2816
    'oS' # status flag (success)
2817
    's\x00\x00\x00\x08l4:argse' # args struct ('args,')
2818
    'b\x00\x00\x00\x03aaa' # body part ('aaa')
2819
    'b\x00\x00\x00\x03bbb' # body part ('bbb')
2820
    'oE' # status flag (error)
2821
    's\x00\x00\x00\x10l5:error5:Boom!e' # err struct ('error', 'Boom!')
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.
2402.1.2 by Andrew Bennetts
Deal with review comments.
3520
        self._captureVar('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
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