~bzr-pqm/bzr/bzr.dev

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