/brz/remove-bazaar

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