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