/brz/remove-bazaar

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