/brz/remove-bazaar

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