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