~bzr-pqm/bzr/bzr.dev

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