/brz/remove-bazaar

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