/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2006-2011 Canonical Ltd
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
16
17
"""Tests for smart transport"""
18
19
# all of this deals with byte strings so this is safe
20
from cStringIO import StringIO
6133.4.55 by John Arbash Meinel
Now we've implemented the basic structure.
21
import doctest
4797.85.22 by John Arbash Meinel
Pull out portable_socket_pair.
22
import errno
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
23
import os
24
import socket
4797.85.9 by John Arbash Meinel
Start writing a test of how subprocess handles writing to a closed connection.
25
import subprocess
6133.4.10 by John Arbash Meinel
Handle the win32 not-a-socket errors. I think this is ~ready. At least for feedback.
26
import sys
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
27
import threading
6133.4.43 by John Arbash Meinel
Initial implementation of SIGHUP for bzr serve. bug #795025.
28
import time
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
29
6133.4.55 by John Arbash Meinel
Now we've implemented the basic structure.
30
from testtools.matchers import DocTestMatches
31
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
32
import bzrlib
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
33
from bzrlib import (
34
        bzrdir,
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)
1456
        # It should also not be fully stopped
1457
        server._fully_stopped.wait(0.01)
1458
        self.assertFalse(server._fully_stopped.isSet())
6133.4.58 by John Arbash Meinel
Fix the race condition.
1459
        response_handler.read_body_bytes()
6133.4.54 by John Arbash Meinel
Teach the SmartTCPServer to wait gracefully for the client threads to exit.
1460
        client_sock.close()
1461
        server_side_thread.join()
1462
        server_thread.join()
1463
        self.assertTrue(server._fully_stopped.isSet())
1464
        log = self.get_log()
6133.4.55 by John Arbash Meinel
Now we've implemented the basic structure.
1465
        self.assertThat(log, DocTestMatches("""\
1466
    INFO  Requested to stop gracefully
6133.4.62 by John Arbash Meinel
Add a nicer repr for shutting down.
1467
... Stopping SmartServerSocketStreamMedium(client=('127.0.0.1', ...
6133.4.55 by John Arbash Meinel
Now we've implemented the basic structure.
1468
    INFO  Waiting for 1 client(s) to finish
1469
""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
1470
1471
    def test_stop_gracefully_tells_handlers_to_stop(self):
1472
        server, server_thread = self.make_server()
1473
        client_sock = self.connect_to_server(server)
1474
        self.say_hello(client_sock)
1475
        server_handler, server_side_thread = server._active_connections[0]
1476
        self.assertFalse(server_handler.finished)
1477
        server._stop_gracefully()
1478
        self.assertTrue(server_handler.finished)
1479
        client_sock.close()
1480
        self.connect_to_server_and_hangup(server)
1481
        server_thread.join()
6133.4.54 by John Arbash Meinel
Teach the SmartTCPServer to wait gracefully for the client threads to exit.
1482
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1483
1484
class SmartTCPTests(tests.TestCase):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1485
    """Tests for connection/end to end behaviour using the TCP server.
1486
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1487
    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
1488
    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`.
1489
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1490
    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
1491
    """
1492
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1493
    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`.
1494
        """Setup the server.
1495
1496
        :param readonly: Create a readonly server.
1497
        """
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.
1498
        # NB: Tests using this fall into two categories: tests of the server,
1499
        # tests wanting a server. The latter should be updated to use
1500
        # self.vfs_transport_factory etc.
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1501
        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.
1502
            mem_server = memory.MemoryServer()
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1503
            mem_server.start_server()
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
1504
            self.addCleanup(mem_server.stop_server)
4634.47.10 by Andrew Bennetts
Merge bzr.dev; fix test isolation glitch.
1505
            self.permit_url(mem_server.get_url())
6138.1.1 by John Arbash Meinel
Change the import lines.
1506
            self.backing_transport = _mod_transport.get_transport_from_url(
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1507
                mem_server.get_url())
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1508
        else:
1509
            self.backing_transport = backing_transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1510
        if readonly:
1511
            self.real_backing_transport = self.backing_transport
6138.1.1 by John Arbash Meinel
Change the import lines.
1512
            self.backing_transport = _mod_transport.get_transport_from_url(
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
1513
                "readonly+" + self.backing_transport.abspath('.'))
6133.4.26 by John Arbash Meinel
get rid of the default timeout parameters.
1514
        self.server = _mod_server.SmartTCPServer(self.backing_transport,
1515
                                                 client_timeout=4.0)
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1516
        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.
1517
        self.server.start_background_thread('-' + self.id())
2413.2.1 by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc.
1518
        self.transport = remote.RemoteTCPTransport(self.server.get_url())
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1519
        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.
1520
        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
1521
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1522
    def stop_server(self):
1523
        """Disconnect the client and stop the server.
1524
1525
        This must be re-entrant as some tests will call it explicitly in
1526
        addition to the normal cleanup.
1527
        """
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, 'transport', None):
1529
            self.transport.disconnect()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1530
            del self.transport
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1531
        if getattr(self, 'server', None):
1532
            self.server.stop_background_thread()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1533
            del self.server
1534
1535
1536
class TestServerSocketUsage(SmartTCPTests):
1537
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1538
    def test_server_start_stop(self):
1539
        """It should be safe to stop the server with no requests."""
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1540
        self.start_server()
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1541
        t = remote.RemoteTCPTransport(self.server.get_url())
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1542
        self.stop_server()
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1543
        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.
1544
1545
    def test_server_closes_listening_sock_on_shutdown_after_request(self):
2370.4.2 by Robert Collins
Review feedback.
1546
        """The server should close its listening socket when it's stopped."""
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1547
        self.start_server()
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1548
        server_url = self.server.get_url()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1549
        self.transport.has('.')
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1550
        self.stop_server()
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1551
        # if the listening socket has closed, we should get a BADFD error
1552
        # when connecting, rather than a hang.
5247.2.34 by Vincent Ladeuil
Merge sftp-leaks into catch-them-all resolving conflicts
1553
        t = remote.RemoteTCPTransport(server_url)
5247.3.48 by Vincent Ladeuil
Fixed as per lifeless suggestion.
1554
        self.assertRaises(errors.ConnectionError, t.has, '.')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1555
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1556
1557
class WritableEndToEndTests(SmartTCPTests):
1558
    """Client to server tests that require a writable transport."""
1559
1560
    def setUp(self):
1561
        super(WritableEndToEndTests, self).setUp()
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1562
        self.start_server()
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1563
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1564
    def test_start_tcp_server(self):
1565
        url = self.server.get_url()
1566
        self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/')
1567
1568
    def test_smart_transport_has(self):
1569
        """Checking for file existence over smart."""
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1570
        self.overrideEnv('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1571
        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
1572
        self.assertTrue(self.transport.has("foo"))
1573
        self.assertFalse(self.transport.has("non-foo"))
1574
1575
    def test_smart_transport_get(self):
1576
        """Read back a file over smart."""
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1577
        self.overrideEnv('BZR_NO_SMART_VFS', None)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1578
        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
1579
        fp = self.transport.get("foo")
1580
        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`.
1581
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1582
    def test_get_error_enoent(self):
1583
        """Error reported from server getting nonexistent file."""
1752.2.81 by Andrew Bennetts
Merge cleaned up underlying dependencies for remote bzrdir.
1584
        # The path in a raised NoSuchFile exception should be the precise path
1585
        # asked for by the client. This gives meaningful and unsurprising errors
1586
        # for users.
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1587
        self.overrideEnv('BZR_NO_SMART_VFS', None)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1588
        err = self.assertRaises(
1589
            errors.NoSuchFile, self.transport.get, 'not%20a%20file')
4294.2.9 by Robert Collins
Fixup tests broken by cleaning up the layering.
1590
        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
1591
1592
    def test_simple_clone_conn(self):
1593
        """Test that cloning reuses the same connection."""
1594
        # we create a real connection not a loopback one, but it will use the
1595
        # 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__.
1596
        conn2 = self.transport.clone('.')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1597
        self.assertIs(self.transport.get_smart_medium(),
1598
                      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
1599
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)
1600
    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
1601
        self.assertEquals('/foo/bar',
1602
                          self.transport._remote_path('foo/bar'))
1603
1604
    def test_clone_changes_base(self):
1605
        """Cloning transport produces one with a new base location"""
1606
        conn2 = self.transport.clone('subdir')
1607
        self.assertEquals(self.transport.base + 'subdir/',
1608
                          conn2.base)
1609
1610
    def test_open_dir(self):
1611
        """Test changing directory"""
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1612
        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
1613
        transport = self.transport
1614
        self.backing_transport.mkdir('toffee')
1615
        self.backing_transport.mkdir('toffee/apple')
1616
        self.assertEquals('/toffee', transport._remote_path('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1617
        toffee_trans = transport.clone('toffee')
1618
        # Check that each transport has only the contents of its directory
1619
        # directly visible. If state was being held in the wrong object, it's
1620
        # conceivable that cloning a transport would alter the state of the
1621
        # cloned-from transport.
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1622
        self.assertTrue(transport.has('toffee'))
1910.19.13 by Andrew Bennetts
Address various review comments.
1623
        self.assertFalse(toffee_trans.has('toffee'))
1624
        self.assertFalse(transport.has('apple'))
1625
        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
1626
1627
    def test_open_bzrdir(self):
1628
        """Open an existing bzrdir over smart transport"""
1629
        transport = self.transport
1630
        t = self.backing_transport
1631
        bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t)
6472.2.3 by Jelmer Vernooij
More control dir.
1632
        result_dir = controldir.ControlDir.open_containing_from_transport(
1633
            transport)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1634
1635
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1636
class ReadOnlyEndToEndTests(SmartTCPTests):
1637
    """Tests from the client to the server using a readonly backing transport."""
1638
1639
    def test_mkdir_error_readonly(self):
1640
        """TransportNotPossible should be preserved from the backing transport."""
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1641
        self.overrideEnv('BZR_NO_SMART_VFS', None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1642
        self.start_server(readonly=True)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1643
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1644
            'foo')
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1645
1646
1647
class TestServerHooks(SmartTCPTests):
1648
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1649
    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
1650
        """Record a server_started|stopped hook firing."""
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1651
        self.hook_calls.append((backing_urls, public_url))
1652
1653
    def test_server_started_hook_memory(self):
1654
        """The server_started hook fires when the server is started."""
1655
        self.hook_calls = []
6138.1.1 by John Arbash Meinel
Change the import lines.
1656
        _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.
1657
            self.capture_server_call, None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1658
        self.start_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1659
        # at this point, the server will be starting a thread up.
1660
        # there is no indicator at the moment, so bodge it by doing a request.
1661
        self.transport.has('.')
1662
        # The default test server uses MemoryTransport and that has no external
1663
        # url:
1664
        self.assertEqual([([self.backing_transport.base], self.transport.base)],
1665
            self.hook_calls)
1666
1667
    def test_server_started_hook_file(self):
1668
        """The server_started hook fires when the server is started."""
1669
        self.hook_calls = []
6138.1.1 by John Arbash Meinel
Change the import lines.
1670
        _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.
1671
            self.capture_server_call, None)
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1672
        self.start_server(
6138.1.1 by John Arbash Meinel
Change the import lines.
1673
            backing_transport=_mod_transport.get_transport_from_path("."))
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1674
        # at this point, the server will be starting a thread up.
1675
        # there is no indicator at the moment, so bodge it by doing a request.
1676
        self.transport.has('.')
1677
        # The default test server uses MemoryTransport and that has no external
1678
        # url:
1679
        self.assertEqual([([
1680
            self.backing_transport.base, self.backing_transport.external_url()],
1681
             self.transport.base)],
1682
            self.hook_calls)
1683
1684
    def test_server_stopped_hook_simple_memory(self):
1685
        """The server_stopped hook fires when the server is stopped."""
1686
        self.hook_calls = []
6138.1.1 by John Arbash Meinel
Change the import lines.
1687
        _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.
1688
            self.capture_server_call, None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
1689
        self.start_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1690
        result = [([self.backing_transport.base], self.transport.base)]
1691
        # check the stopping message isn't emitted up front.
1692
        self.assertEqual([], self.hook_calls)
1693
        # nor after a single message
1694
        self.transport.has('.')
1695
        self.assertEqual([], self.hook_calls)
1696
        # clean up the server
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1697
        self.stop_server()
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1698
        # now it should have fired.
1699
        self.assertEqual(result, self.hook_calls)
1700
1701
    def test_server_stopped_hook_simple_file(self):
1702
        """The server_stopped hook fires when the server is stopped."""
1703
        self.hook_calls = []
6138.1.1 by John Arbash Meinel
Change the import lines.
1704
        _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.
1705
            self.capture_server_call, None)
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1706
        self.start_server(
6138.1.1 by John Arbash Meinel
Change the import lines.
1707
            backing_transport=_mod_transport.get_transport_from_path("."))
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
1708
        result = [(
1709
            [self.backing_transport.base, self.backing_transport.external_url()]
1710
            , 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.
1711
        # check the stopping message isn't emitted up front.
1712
        self.assertEqual([], self.hook_calls)
1713
        # nor after a single message
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1714
        self.transport.has('.')
1715
        self.assertEqual([], self.hook_calls)
1716
        # clean up the server
5247.2.9 by Vincent Ladeuil
The smart server leaks one thread (daemonic) for each connection.
1717
        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.
1718
        # now it should have fired.
2370.4.1 by Robert Collins
New SmartServer hooks facility. There are two initial hooks documented
1719
        self.assertEqual(result, self.hook_calls)
1720
1721
# TODO: test that when the server suffers an exception that it calls the
1722
# server-stopped hook.
1723
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1724
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1725
class SmartServerCommandTests(tests.TestCaseWithTransport):
1726
    """Tests that call directly into the command objects, bypassing the network
1727
    and the request dispatching.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
1728
1729
    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.
1730
    test_smart.py.
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1731
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1732
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1733
    def test_hello(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1734
        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)
1735
        response = cmd.execute()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1736
        self.assertEqual(('ok', '2'), response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1737
        self.assertEqual(None, response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1738
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1739
    def test_get_bundle(self):
1740
        from bzrlib.bundle import serializer
1741
        wt = self.make_branch_and_tree('.')
1910.19.13 by Andrew Bennetts
Address various review comments.
1742
        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
1743
        wt.add('hello')
1910.19.13 by Andrew Bennetts
Address various review comments.
1744
        rev_id = wt.commit('add hello')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1745
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1746
        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)
1747
        response = cmd.execute('.', rev_id)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1748
        bundle = serializer.read_bundle(StringIO(response.body))
1749
        self.assertEqual((), response.args)
1750
1751
1752
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
1753
    """Test that call directly into the handler logic, bypassing the network."""
1754
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
    def setUp(self):
1756
        super(SmartServerRequestHandlerTests, self).setUp()
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1757
        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)
1758
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1759
    def build_handler(self, transport):
1760
        """Returns a handler for the commands in protocol version one."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1761
        return _mod_request.SmartServerRequestHandler(
1762
            transport, _mod_request.request_handlers, '/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1763
1764
    def test_construct_request_handler(self):
1765
        """Constructing a request handler should be easy and set defaults."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1766
        handler = _mod_request.SmartServerRequestHandler(None, commands=None,
1767
                root_client_path='/')
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1768
        self.assertFalse(handler.finished_reading)
1769
1770
    def test_hello(self):
1771
        handler = self.build_handler(None)
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1772
        handler.args_received(('hello',))
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1773
        self.assertEqual(('ok', '2'), handler.response.args)
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1774
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1775
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
1776
    def test_disable_vfs_handler_classes_via_environment(self):
2018.5.140 by Andrew Bennetts
Merge from bzr.dev
1777
        # VFS handler classes will raise an error from "execute" if
1778
        # BZR_NO_SMART_VFS is set.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1779
        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)
1780
        # set environment variable after construction to make sure it's
1781
        # examined.
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1782
        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)
1783
        self.assertRaises(errors.DisabledMethod, handler.execute)
1784
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1785
    def test_readonly_exception_becomes_transport_not_possible(self):
1786
        """The response for a read-only error is ('ReadOnlyError')."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1787
        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`.
1788
        # 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.
1789
        handler.args_received(('mkdir', 'foo', ''))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1790
        # and the failure should be an explicit ReadOnlyError
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1791
        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`.
1792
        # XXX: TODO: test that other TransportNotPossible errors are
1793
        # presented as TransportNotPossible - not possible to do that
1794
        # until I figure out how to trigger that relatively cleanly via
1795
        # the api. RBC 20060918
1796
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1797
    def test_hello_has_finished_body_on_dispatch(self):
1798
        """The 'hello' command should set finished_reading."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1799
        handler = self.build_handler(None)
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1800
        handler.args_received(('hello',))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1801
        self.assertTrue(handler.finished_reading)
1802
        self.assertNotEqual(None, handler.response)
1803
1804
    def test_put_bytes_non_atomic(self):
1805
        """'put_...' should set finished_reading after reading the bytes."""
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1806
        handler = self.build_handler(self.get_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1807
        handler.args_received(('put_non_atomic', 'a-file', '', 'F', ''))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1808
        self.assertFalse(handler.finished_reading)
1809
        handler.accept_body('1234')
1810
        self.assertFalse(handler.finished_reading)
1811
        handler.accept_body('5678')
1812
        handler.end_of_body()
1813
        self.assertTrue(handler.finished_reading)
1814
        self.assertEqual(('ok', ), handler.response.args)
1815
        self.assertEqual(None, handler.response.body)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1816
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1817
    def test_readv_accept_body(self):
1818
        """'readv' should set finished_reading after reading offsets."""
1819
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1820
        handler = self.build_handler(self.get_readonly_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1821
        handler.args_received(('readv', 'a-file'))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1822
        self.assertFalse(handler.finished_reading)
1823
        handler.accept_body('2,')
1824
        self.assertFalse(handler.finished_reading)
1825
        handler.accept_body('3')
1826
        handler.end_of_body()
1827
        self.assertTrue(handler.finished_reading)
1828
        self.assertEqual(('readv', ), handler.response.args)
1829
        # co - nte - nt of a-file is the file contents we are extracting from.
1830
        self.assertEqual('nte', handler.response.body)
1831
1832
    def test_readv_short_read_response_contents(self):
1833
        """'readv' when a short read occurs sets the response appropriately."""
1834
        self.build_tree(['a-file'])
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
1835
        handler = self.build_handler(self.get_readonly_transport())
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
1836
        handler.args_received(('readv', 'a-file'))
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1837
        # read beyond the end of the file.
1838
        handler.accept_body('100,1')
1839
        handler.end_of_body()
1840
        self.assertTrue(handler.finished_reading)
2692.1.8 by Andrew Bennetts
Fix trivial test failure.
1841
        self.assertEqual(('ShortReadvError', './a-file', '100', '1', '0'),
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
1842
            handler.response.args)
1843
        self.assertEqual(None, handler.response.body)
1844
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1845
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)
1846
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.
1847
1848
    def test_registration(self):
6138.1.1 by John Arbash Meinel
Change the import lines.
1849
        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.
1850
        self.assertIsInstance(t, remote.RemoteSSHTransport)
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
1851
        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.
1852
2814.2.2 by Martin Pool
merge bzr+https patch from johnf and add a basic test
1853
    def test_bzr_https(self):
1854
        # https://bugs.launchpad.net/bzr/+bug/128456
6138.1.1 by John Arbash Meinel
Change the import lines.
1855
        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
1856
        self.assertIsInstance(t, remote.RemoteHTTPTransport)
1857
        self.assertStartsWith(
1858
            t._http_transport.base,
1859
            'https://')
1860
1752.2.73 by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor.
1861
2018.5.20 by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts)
1862
class TestRemoteTransport(tests.TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1863
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1864
    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)
1865
        # 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.
1866
        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.
1867
        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.
1868
        client_medium = medium.SmartSimplePipesClientMedium(
1869
            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)
1870
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1871
            '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.
1872
        # 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).
1873
        client_medium._protocol_version = 1
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1874
1875
        # 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.
1876
        # method is called.  No data should have been sent, or read.
1877
        self.assertEqual(0, input.tell())
1878
        self.assertEqual('', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1879
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1880
        # 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.
1881
        # transport makes its own protocol instances, we check on the wire.
1882
        # XXX: TODO: give the transport a protocol factory, which can make
1883
        # an instrumented protocol for us.
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1884
        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.
1885
        # 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.
1886
        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.
1887
        self.assertEqual('get\x01/foo\n', output.getvalue())
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
1888
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1889
    def test__translate_error_readonly(self):
1890
        """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.
1891
        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)
1892
        transport = remote.RemoteTransport(
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1893
            'bzr://localhost/', medium=client_medium)
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1894
        err = errors.ErrorFromSmartServer(("ReadOnlyError", ))
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1895
        self.assertRaises(errors.TransportNotPossible,
3779.3.2 by Andrew Bennetts
Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
1896
            transport._translate_error, err)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
1897
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
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1899
class TestSmartProtocol(tests.TestCase):
1900
    """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.
1901
1902
    Each test case gets a smart_server and smart_client created during setUp().
1903
1904
    It is planned that the client can be called with self.call_client() giving
1905
    it an expected server response, which will be fed into it when it tries to
1906
    read. Likewise, self.call_server will call a servers method with a canned
1907
    serialised client request. Output done by the client or server for these
1908
    calls will be captured to self.to_server and self.to_client. Each element
1909
    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.
1910
1911
    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.
1912
    """
1913
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1914
    request_encoder = None
1915
    response_decoder = None
1916
    server_protocol_class = None
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1917
    client_protocol_class = None
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1918
1919
    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.
1920
        """
1921
        :returns: a Request
1922
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1923
        # This is very similar to
1924
        # 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.
1925
        # XXX: make this use _SmartClient!
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1926
        if input_bytes is None:
1927
            input = StringIO()
1928
        else:
1929
            input = StringIO(input_bytes)
1930
        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.
1931
        client_medium = medium.SmartSimplePipesClientMedium(
1932
            input, output, 'base')
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1933
        request = client_medium.get_request()
1934
        if self.client_protocol_class is not None:
1935
            client_protocol = self.client_protocol_class(request)
1936
            return client_protocol, client_protocol, output
1937
        else:
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
1938
            self.assertNotEqual(None, self.request_encoder)
1939
            self.assertNotEqual(None, self.response_decoder)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1940
            requester = self.request_encoder(request)
1941
            response_handler = message.ConventionalResponseHandler()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1942
            response_protocol = self.response_decoder(
1943
                response_handler, expect_version_marker=True)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
1944
            response_handler.setProtoAndMediumRequest(
1945
                response_protocol, request)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1946
            return requester, response_handler, output
1947
1948
    def make_client_protocol(self, input_bytes=None):
1949
        result = self.make_client_protocol_and_output(input_bytes=input_bytes)
1950
        requester, response_handler, output = result
1951
        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.
1952
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1953
    def make_server_protocol(self):
1954
        out_stream = StringIO()
3245.4.34 by Andrew Bennetts
Remove another insignificant change vs. bzr.dev.
1955
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1956
        return smart_protocol, out_stream
1957
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.
1958
    def setUp(self):
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
1959
        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.
1960
        self.response_marker = getattr(
1961
            self.client_protocol_class, 'response_marker', None)
1962
        self.request_marker = getattr(
1963
            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.
1964
1965
    def assertOffsetSerialisation(self, expected_offsets, expected_serialised,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1966
        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.
1967
        """Check that smart (de)serialises offsets as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1968
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.
1969
        We check both serialisation and deserialisation at the same time
1970
        to ensure that the round tripping cannot skew: both directions should
1971
        be as expected.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1972
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.
1973
        :param expected_offsets: a readv offset list.
1974
        :param expected_seralised: an expected serial form of the offsets.
1975
        """
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
        # XXX: '_deserialise_offsets' should be a method of the
1977
        # SmartServerRequestProtocol in future.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1978
        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.
1979
        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.
1980
        self.assertEqual(expected_offsets, offsets)
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
1981
        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.
1982
        self.assertEqual(expected_serialised, serialised)
1983
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
1984
    def build_protocol_waiting_for_body(self):
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
1985
        smart_protocol, out_stream = self.make_server_protocol()
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1986
        smart_protocol._has_dispatched = True
3245.1.14 by Andrew Bennetts
Merge from bzr.dev
1987
        smart_protocol.request = _mod_request.SmartServerRequestHandler(
1988
            None, _mod_request.request_handlers, '/')
5340.15.1 by John Arbash Meinel
supersede exc-info branch
1989
        # 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.
1990
        class FakeCommand(_mod_request.SmartServerRequest):
1991
            def do_body(self_cmd, body_bytes):
2018.5.7 by Andrew Bennetts
Simplify dispatch_command.
1992
                self.end_received = True
1993
                self.assertEqual('abcdefg', body_bytes)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
1994
                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.
1995
        smart_protocol.request._command = FakeCommand(None)
2400.1.4 by Andrew Bennetts
Tidy up accidental changes.
1996
        # Call accept_bytes to make sure that internal state like _body_decoder
1997
        # is initialised.  This test should probably be given a clearer
1998
        # interface to work with that will not cause this inconsistency.
1999
        #   -- 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
2000
        smart_protocol.accept_bytes('')
2001
        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.
2002
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
2003
    def assertServerToClientEncoding(self, expected_bytes, expected_tuple,
2004
            input_tuples):
2005
        """Assert that each input_tuple serialises as expected_bytes, and the
2006
        bytes deserialise as expected_tuple.
2007
        """
2008
        # check the encoding of the server for all input_tuples matches
2009
        # expected bytes
2010
        for input_tuple in input_tuples:
3245.1.11 by Andrew Bennetts
Add make_server_protocol helper to TestSmartProtocol.
2011
            server_protocol, server_output = self.make_server_protocol()
2432.4.4 by Robert Collins
Merge hpss-protocol2.
2012
            server_protocol._send_response(
2013
                _mod_request.SuccessfulSmartServerResponse(input_tuple))
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
2014
            self.assertEqual(expected_bytes, server_output.getvalue())
2015
        # 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.
2016
        requester, response_handler = self.make_client_protocol(expected_bytes)
2017
        requester.call('foo')
2018
        self.assertEqual(expected_tuple, response_handler.read_response_tuple())
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
2019
2020
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.
2021
class CommonSmartProtocolTestMixin(object):
2022
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
2023
    def test_connection_closed_reporting(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2024
        requester, response_handler = self.make_client_protocol()
2025
        requester.call('hello')
3245.1.10 by Andrew Bennetts
Remove trailing whitespace.
2026
        ex = self.assertRaises(errors.ConnectionReset,
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2027
            response_handler.read_response_tuple)
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
2028
        self.assertEqual("Connection closed: "
4509.2.3 by Martin Pool
Test tweaks for ConnectionReset message change
2029
            "Unexpected end of message. Please check connectivity "
2030
            "and permissions, and report a bug if problems persist. ",
4070.8.1 by Martin Pool
Remove 'try -Dhpss' from error messages
2031
            str(ex))
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
2032
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
2033
    def test_server_offset_serialisation(self):
2034
        """The Smart protocol serialises offsets as a comma and \n string.
2035
2036
        We check a number of boundary cases are as expected: empty, one offset,
2037
        one with the order of reads not increasing (an out of order read), and
2038
        one that should coalesce.
2039
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2040
        requester, response_handler = self.make_client_protocol()
2041
        self.assertOffsetSerialisation([], '', requester)
2042
        self.assertOffsetSerialisation([(1,2)], '1,2', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
2043
        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.
2044
            requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
2045
        self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)],
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2046
            '1,2\n3,4\n100,200', requester)
3245.1.8 by Andrew Bennetts
Remove TestSmartProtocol.setUp entirely.
2047
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.
2048
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.
2049
class TestVersionOneFeaturesInProtocolOne(
2050
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2051
    """Tests for version one smart protocol features as implemeted by version
2052
    one."""
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
2053
2054
    client_protocol_class = protocol.SmartClientRequestProtocolOne
2055
    server_protocol_class = protocol.SmartServerRequestProtocolOne
2056
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2057
    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
2058
        smart_protocol = protocol.SmartServerRequestProtocolOne(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2059
        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
2060
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2061
        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
2062
        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.
2063
2064
    def test_construct_version_one_client_protocol(self):
2065
        # we can construct a client protocol from a client medium request
2066
        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.
2067
        client_medium = medium.SmartSimplePipesClientMedium(
2068
            None, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2069
        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
2070
        client_protocol = protocol.SmartClientRequestProtocolOne(request)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2071
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
2072
    def test_accept_bytes_of_bad_request_to_protocol(self):
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2073
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2074
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2075
            None, out_stream.write)
2076
        smart_protocol.accept_bytes('abc')
2077
        self.assertEqual('abc', smart_protocol.in_buffer)
2078
        smart_protocol.accept_bytes('\n')
2079
        self.assertEqual(
2080
            "error\x01Generic bzr smart protocol error: bad request 'abc'\n",
2081
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2082
        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
2083
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
2084
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2085
    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.
2086
        protocol = self.build_protocol_waiting_for_body()
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
2087
        self.assertEqual(6, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2088
        protocol.accept_bytes('7\nabc')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
2089
        self.assertEqual(9, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2090
        protocol.accept_bytes('defgd')
2091
        protocol.accept_bytes('one\n')
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
2092
        self.assertEqual(0, protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2093
        self.assertTrue(self.end_received)
2094
2018.2.14 by Andrew Bennetts
Seperate SmartServer{Pipe,Socket}StreamMedium out of SmartServerStreamMedium. Use recv to make the socket server medium better.
2095
    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.
2096
        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.
2097
        mem_transport = memory.MemoryTransport()
2098
        mem_transport.put_bytes('foo', 'abcdefghij')
2099
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2100
        smart_protocol = protocol.SmartServerRequestProtocolOne(mem_transport,
2018.2.23 by Andrew Bennetts
Clean up SmartServerStreamMedium implementations, including removing unnecessary flushes.
2101
                out_stream.write)
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2102
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
2103
        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.
2104
        self.assertEqual('readv\n3\ndefdone\n', out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2105
        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
2106
        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.
2107
2018.2.10 by Andrew Bennetts
Tidy up TODOs, further testing and fixes for SmartServerRequestProtocolOne, and remove a read_bytes(1) call.
2108
    def test_accept_excess_bytes_are_preserved(self):
2109
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2110
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2111
            None, out_stream.write)
2112
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2113
        self.assertEqual("ok\x012\n", out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2114
        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
2115
        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.
2116
2117
    def test_accept_excess_bytes_after_body(self):
2118
        protocol = self.build_protocol_waiting_for_body()
2119
        protocol.accept_bytes('7\nabcdefgdone\nX')
2120
        self.assertTrue(self.end_received)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2121
        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.
2122
        self.assertEqual("", protocol.in_buffer)
2123
        protocol.accept_bytes('Y')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2124
        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.
2125
        self.assertEqual("", protocol.in_buffer)
2126
2127
    def test_accept_excess_bytes_after_dispatch(self):
2128
        out_stream = StringIO()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2129
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2130
            None, out_stream.write)
2131
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2132
        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
2133
        smart_protocol.accept_bytes('hel')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2134
        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
2135
        smart_protocol.accept_bytes('lo\n')
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2136
        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
2137
        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.
2138
2018.3.2 by Andrew Bennetts
Ensure that a request's next_read_size() is 0 once an error response is sent.
2139
    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
2140
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2141
            None, lambda x: None)
2142
        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.
2143
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2144
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2145
        self.assertEqual(0, smart_protocol.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2146
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
2147
    def test__send_response_errors_with_base_response(self):
2148
        """Ensure that only the Successful/Failed subclasses are used."""
2149
        smart_protocol = protocol.SmartServerRequestProtocolOne(
2150
            None, lambda x: None)
2151
        self.assertRaises(AttributeError, smart_protocol._send_response,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2152
            _mod_request.SmartServerResponse(('x',)))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
2153
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
2154
    def test_query_version(self):
2155
        """query_version on a SmartClientProtocolOne should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2156
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2157
        The protocol provides the query_version because the domain level clients
2158
        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.
2159
        """
2160
        # What we really want to test here is that SmartClientProtocolOne calls
2161
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
4031.3.1 by Frank Aspell
Fixing various typos
2162
        # 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.
2163
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2164
        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.
2165
        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.
2166
        client_medium = medium.SmartSimplePipesClientMedium(
2167
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2168
        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
2169
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2170
        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.
2171
2172
    def test_client_call_empty_response(self):
2173
        # protocol.call() can get back an empty tuple as a response. This occurs
2174
        # when the parsed line is an empty line, and results in a tuple with
2175
        # one element - an empty string.
2176
        self.assertServerToClientEncoding('\n', ('', ), [(), ('', )])
2177
2178
    def test_client_call_three_element_response(self):
2179
        # protocol.call() can get back tuples of other lengths. A three element
2180
        # tuple should be unpacked as three strings.
2181
        self.assertServerToClientEncoding('a\x01b\x0134\n', ('a', 'b', '34'),
2182
            [('a', 'b', '34')])
2183
2184
    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.
2185
        # 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.
2186
        # wire.
2187
        expected_bytes = "foo\n7\nabcdefgdone\n"
2188
        input = StringIO("\n")
2189
        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.
2190
        client_medium = medium.SmartSimplePipesClientMedium(
2191
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2192
        request = client_medium.get_request()
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
2193
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2194
        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.
2195
        self.assertEqual(expected_bytes, output.getvalue())
2196
2197
    def test_client_call_with_body_readv_array(self):
2198
        # protocol.call_with_upload should encode the readv array and then
2199
        # length-prefix the bytes onto the wire.
2200
        expected_bytes = "foo\n7\n1,2\n5,6done\n"
2201
        input = StringIO("\n")
2202
        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.
2203
        client_medium = medium.SmartSimplePipesClientMedium(
2204
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2205
        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
2206
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2207
        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.
2208
        self.assertEqual(expected_bytes, output.getvalue())
2209
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.
2210
    def _test_client_read_response_tuple_raises_UnknownSmartMethod(self,
2211
            server_bytes):
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
2212
        input = StringIO(server_bytes)
2213
        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.
2214
        client_medium = medium.SmartSimplePipesClientMedium(
2215
            input, output, 'base')
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
2216
        request = client_medium.get_request()
2217
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2218
        smart_protocol.call('foo')
2219
        self.assertRaises(
2220
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2221
        # The request has been finished.  There is no body to read, and
2222
        # attempts to read one will fail.
2223
        self.assertRaises(
2224
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2225
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
2226
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2227
        """read_response_tuple raises UnknownSmartMethod if the response says
2228
        the server did not recognise the request.
2229
        """
2230
        server_bytes = (
2231
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2232
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
2233
            server_bytes)
2234
2235
    def test_client_read_response_tuple_raises_UnknownSmartMethod_0_11(self):
2236
        """read_response_tuple also raises UnknownSmartMethod if the response
2237
        from a bzr 0.11 says the server did not recognise the request.
2238
2239
        (bzr 0.11 sends a slightly different error message to later versions.)
2240
        """
2241
        server_bytes = (
2242
            "error\x01Generic bzr smart protocol error: bad request u'foo'\n")
2243
        self._test_client_read_response_tuple_raises_UnknownSmartMethod(
2244
            server_bytes)
2245
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
2246
    def test_client_read_body_bytes_all(self):
2247
        # read_body_bytes should decode the body bytes from the wire into
2248
        # a response.
2249
        expected_bytes = "1234567"
2250
        server_bytes = "ok\n7\n1234567done\n"
2251
        input = StringIO(server_bytes)
2252
        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.
2253
        client_medium = medium.SmartSimplePipesClientMedium(
2254
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2255
        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
2256
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2257
        smart_protocol.call('foo')
2258
        smart_protocol.read_response_tuple(True)
2259
        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.
2260
2261
    def test_client_read_body_bytes_incremental(self):
2262
        # test reading a few bytes at a time from the body
2263
        # 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.
2264
        # 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.
2265
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
2266
        # that.
2267
        expected_bytes = "1234567"
2268
        server_bytes = "ok\n7\n1234567done\n"
2269
        input = StringIO(server_bytes)
2270
        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.
2271
        client_medium = medium.SmartSimplePipesClientMedium(
2272
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2273
        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
2274
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2275
        smart_protocol.call('foo')
2276
        smart_protocol.read_response_tuple(True)
2277
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2278
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2279
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2280
        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.
2281
2282
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2283
        # cancelling the expected body needs to finish the request, but not
2284
        # read any more bytes.
2285
        expected_bytes = "1234567"
2286
        server_bytes = "ok\n7\n1234567done\n"
2287
        input = StringIO(server_bytes)
2288
        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.
2289
        client_medium = medium.SmartSimplePipesClientMedium(
2290
            input, output, 'base')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
2291
        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
2292
        smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2293
        smart_protocol.call('foo')
2294
        smart_protocol.read_response_tuple(True)
2295
        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.
2296
        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
2297
        self.assertRaises(
2298
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
2299
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2300
    def test_client_read_body_bytes_interrupted_connection(self):
2301
        server_bytes = "ok\n999\nincomplete body"
2302
        input = StringIO(server_bytes)
2303
        output = StringIO()
2304
        client_medium = medium.SmartSimplePipesClientMedium(
2305
            input, output, 'base')
2306
        request = client_medium.get_request()
2307
        smart_protocol = self.client_protocol_class(request)
2308
        smart_protocol.call('foo')
2309
        smart_protocol.read_response_tuple(True)
2310
        self.assertRaises(
2311
            errors.ConnectionReset, smart_protocol.read_body_bytes)
2312
2018.2.15 by Andrew Bennetts
Remove SmartServerRequestProtocolOne.finished_reading attribute, replace with next_read_size method.
2313
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.
2314
class TestVersionOneFeaturesInProtocolTwo(
2315
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2316
    """Tests for version one smart protocol features as implemeted by version
2317
    two.
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2318
    """
2319
2432.2.5 by Andrew Bennetts
Reduce duplication in test_smart_transport.
2320
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
2321
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2322
2323
    def test_construct_version_two_server_protocol(self):
2324
        smart_protocol = protocol.SmartServerRequestProtocolTwo(None, None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2325
        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.
2326
        self.assertEqual('', smart_protocol.in_buffer)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2327
        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.
2328
        self.assertEqual(1, smart_protocol.next_read_size())
2329
2330
    def test_construct_version_two_client_protocol(self):
2331
        # we can construct a client protocol from a client medium request
2332
        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.
2333
        client_medium = medium.SmartSimplePipesClientMedium(
2334
            None, output, 'base')
2432.2.1 by Andrew Bennetts
Add Smart{Client,Server}RequestProtocolTwo, that prefix args tuples with a version marker.
2335
        request = client_medium.get_request()
2336
        client_protocol = protocol.SmartClientRequestProtocolTwo(request)
2337
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2338
    def test_accept_bytes_of_bad_request_to_protocol(self):
2339
        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.
2340
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2341
        smart_protocol.accept_bytes('abc')
2342
        self.assertEqual('abc', smart_protocol.in_buffer)
2343
        smart_protocol.accept_bytes('\n')
2344
        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.
2345
            self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2346
            "failed\nerror\x01Generic bzr smart protocol error: bad request 'abc'\n",
2347
            out_stream.getvalue())
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2348
        self.assertTrue(smart_protocol._has_dispatched)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2349
        self.assertEqual(0, smart_protocol.next_read_size())
2350
2351
    def test_accept_body_bytes_to_protocol(self):
2352
        protocol = self.build_protocol_waiting_for_body()
2353
        self.assertEqual(6, protocol.next_read_size())
2354
        protocol.accept_bytes('7\nabc')
2355
        self.assertEqual(9, protocol.next_read_size())
2356
        protocol.accept_bytes('defgd')
2357
        protocol.accept_bytes('one\n')
2358
        self.assertEqual(0, protocol.next_read_size())
2359
        self.assertTrue(self.end_received)
2360
2361
    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.
2362
        self.overrideEnv('BZR_NO_SMART_VFS', None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2363
        mem_transport = memory.MemoryTransport()
2364
        mem_transport.put_bytes('foo', 'abcdefghij')
2365
        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.
2366
        smart_protocol = self.server_protocol_class(
2367
            mem_transport, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2368
        smart_protocol.accept_bytes('readv\x01foo\n3\n3,3done\n')
2369
        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.
2370
        self.assertEqual(self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2371
                         'success\nreadv\n3\ndefdone\n',
2372
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2373
        self.assertEqual('', smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2374
        self.assertEqual('', smart_protocol.in_buffer)
2375
2376
    def test_accept_excess_bytes_are_preserved(self):
2377
        out_stream = StringIO()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2378
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2379
        smart_protocol.accept_bytes('hello\nhello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2380
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2381
                         out_stream.getvalue())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2382
        self.assertEqual("hello\n", smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2383
        self.assertEqual("", smart_protocol.in_buffer)
2384
2385
    def test_accept_excess_bytes_after_body(self):
2386
        # The excess bytes look like the start of another request.
2387
        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.
2388
        server_protocol.accept_bytes('7\nabcdefgdone\n' + self.response_marker)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2389
        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.
2390
        self.assertEqual(self.response_marker,
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2391
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2392
        self.assertEqual("", server_protocol.in_buffer)
2393
        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.
2394
        self.assertEqual(self.response_marker + "Y",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2395
                         server_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2396
        self.assertEqual("", server_protocol.in_buffer)
2397
2398
    def test_accept_excess_bytes_after_dispatch(self):
2399
        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.
2400
        smart_protocol = self.server_protocol_class(None, out_stream.write)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2401
        smart_protocol.accept_bytes('hello\n')
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2402
        self.assertEqual(self.response_marker + "success\nok\x012\n",
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2403
                         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.
2404
        smart_protocol.accept_bytes(self.request_marker + 'hel')
2405
        self.assertEqual(self.request_marker + "hel",
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
        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.
2408
        self.assertEqual(self.request_marker + "hello\n",
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2409
                         smart_protocol.unused_data)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2410
        self.assertEqual("", smart_protocol.in_buffer)
2411
2412
    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.
2413
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2414
        self.assertEqual(1, smart_protocol.next_read_size())
2415
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2416
            _mod_request.SuccessfulSmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2417
        self.assertEqual(0, smart_protocol.next_read_size())
2418
2419
    def test__send_response_errors_with_base_response(self):
2420
        """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.
2421
        smart_protocol = self.server_protocol_class(None, lambda x: None)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2422
        self.assertRaises(AttributeError, smart_protocol._send_response,
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2423
            _mod_request.SmartServerResponse(('x',)))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2424
2425
    def test_query_version(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2426
        """query_version on a SmartClientProtocolTwo should return a number.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2427
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2428
        The protocol provides the query_version because the domain level clients
2429
        may all need to be able to probe for capabilities.
2430
        """
2431
        # What we really want to test here is that SmartClientProtocolTwo calls
2432
        # accept_bytes(tuple_based_encoding_of_hello) and reads and parses the
4031.3.1 by Frank Aspell
Fixing various typos
2433
        # response of tuple-encoded (ok, 1).  Also, separately we should test
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2434
        # the error if the response is a non-understood version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2435
        input = StringIO(self.response_marker + 'success\nok\x012\n')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2436
        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.
2437
        client_medium = medium.SmartSimplePipesClientMedium(
2438
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2439
        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.
2440
        smart_protocol = self.client_protocol_class(request)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2441
        self.assertEqual(2, smart_protocol.query_version())
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2442
2443
    def test_client_call_empty_response(self):
2444
        # protocol.call() can get back an empty tuple as a response. This occurs
2445
        # when the parsed line is an empty line, and results in a tuple with
2446
        # one element - an empty string.
2447
        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.
2448
            self.response_marker + 'success\n\n', ('', ), [(), ('', )])
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2449
2450
    def test_client_call_three_element_response(self):
2451
        # protocol.call() can get back tuples of other lengths. A three element
2452
        # tuple should be unpacked as three strings.
2453
        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.
2454
            self.response_marker + 'success\na\x01b\x0134\n',
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2455
            ('a', 'b', '34'),
2456
            [('a', 'b', '34')])
2457
2458
    def test_client_call_with_body_bytes_uploads(self):
2459
        # protocol.call_with_body_bytes should length-prefix the bytes onto the
2460
        # 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.
2461
        expected_bytes = self.request_marker + "foo\n7\nabcdefgdone\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2462
        input = StringIO("\n")
2463
        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.
2464
        client_medium = medium.SmartSimplePipesClientMedium(
2465
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2466
        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.
2467
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2468
        smart_protocol.call_with_body_bytes(('foo', ), "abcdefg")
2469
        self.assertEqual(expected_bytes, output.getvalue())
2470
2471
    def test_client_call_with_body_readv_array(self):
2472
        # protocol.call_with_upload should encode the readv array and then
2473
        # 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.
2474
        expected_bytes = self.request_marker + "foo\n7\n1,2\n5,6done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2475
        input = StringIO("\n")
2476
        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.
2477
        client_medium = medium.SmartSimplePipesClientMedium(
2478
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2479
        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.
2480
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2481
        smart_protocol.call_with_body_readv_array(('foo', ), [(1,2),(5,6)])
2482
        self.assertEqual(expected_bytes, output.getvalue())
2483
2484
    def test_client_read_body_bytes_all(self):
2485
        # read_body_bytes should decode the body bytes from the wire into
2486
        # a response.
2487
        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.
2488
        server_bytes = (self.response_marker +
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2489
                        "success\nok\n7\n1234567done\n")
2490
        input = StringIO(server_bytes)
2491
        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.
2492
        client_medium = medium.SmartSimplePipesClientMedium(
2493
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2494
        request = client_medium.get_request()
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
2495
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2496
        smart_protocol.call('foo')
2497
        smart_protocol.read_response_tuple(True)
2498
        self.assertEqual(expected_bytes, smart_protocol.read_body_bytes())
2499
2500
    def test_client_read_body_bytes_incremental(self):
2501
        # test reading a few bytes at a time from the body
2502
        # XXX: possibly we should test dribbling the bytes into the stringio
2503
        # to make the state machine work harder: however, as we use the
2504
        # LengthPrefixedBodyDecoder that is already well tested - we can skip
2505
        # that.
2506
        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.
2507
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2508
        input = StringIO(server_bytes)
2509
        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.
2510
        client_medium = medium.SmartSimplePipesClientMedium(
2511
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2512
        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.
2513
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2514
        smart_protocol.call('foo')
2515
        smart_protocol.read_response_tuple(True)
2516
        self.assertEqual(expected_bytes[0:2], smart_protocol.read_body_bytes(2))
2517
        self.assertEqual(expected_bytes[2:4], smart_protocol.read_body_bytes(2))
2518
        self.assertEqual(expected_bytes[4:6], smart_protocol.read_body_bytes(2))
2519
        self.assertEqual(expected_bytes[6], smart_protocol.read_body_bytes())
2520
2521
    def test_client_cancel_read_body_does_not_eat_body_bytes(self):
2522
        # cancelling the expected body needs to finish the request, but not
2523
        # 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.
2524
        server_bytes = self.response_marker + "success\nok\n7\n1234567done\n"
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2525
        input = StringIO(server_bytes)
2526
        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.
2527
        client_medium = medium.SmartSimplePipesClientMedium(
2528
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2529
        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.
2530
        smart_protocol = self.client_protocol_class(request)
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2531
        smart_protocol.call('foo')
2532
        smart_protocol.read_response_tuple(True)
2533
        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.
2534
        self.assertEqual(len(self.response_marker + 'success\nok\n'),
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2535
                         input.tell())
2536
        self.assertRaises(
2537
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2538
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2539
    def test_client_read_body_bytes_interrupted_connection(self):
2540
        server_bytes = (self.response_marker +
2541
                        "success\nok\n999\nincomplete body")
2542
        input = StringIO(server_bytes)
2543
        output = StringIO()
2544
        client_medium = medium.SmartSimplePipesClientMedium(
2545
            input, output, 'base')
2546
        request = client_medium.get_request()
2547
        smart_protocol = self.client_protocol_class(request)
2548
        smart_protocol.call('foo')
2549
        smart_protocol.read_response_tuple(True)
2550
        self.assertRaises(
2551
            errors.ConnectionReset, smart_protocol.read_body_bytes)
2552
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2553
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.
2554
class TestSmartProtocolTwoSpecificsMixin(object):
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2555
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2556
    def assertBodyStreamSerialisation(self, expected_serialisation,
2557
                                      body_stream):
2558
        """Assert that body_stream is serialised as expected_serialisation."""
2559
        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.
2560
        protocol._send_stream(body_stream, out_stream.write)
2748.4.4 by Andrew Bennetts
Extract a _send_chunks function to make testing easier.
2561
        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.
2562
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.
2563
    def assertBodyStreamRoundTrips(self, body_stream):
2564
        """Assert that body_stream is the same after being serialised and
2565
        deserialised.
2566
        """
2567
        out_stream = StringIO()
2568
        protocol._send_stream(body_stream, out_stream.write)
2569
        decoder = protocol.ChunkedBodyDecoder()
2570
        decoder.accept_bytes(out_stream.getvalue())
2571
        decoded_stream = list(iter(decoder.read_next_chunk, None))
2572
        self.assertEqual(body_stream, decoded_stream)
2573
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2574
    def test_body_stream_serialisation_empty(self):
2575
        """A body_stream with no bytes can be serialised."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2576
        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.
2577
        self.assertBodyStreamRoundTrips([])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2578
2579
    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.
2580
        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.
2581
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2582
            'chunked\n' + '9\nchunk one' + '9\nchunk two' + 'b\nchunk three' +
2583
            '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.
2584
            stream)
2585
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2586
2587
    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.
2588
        """A body stream can include ''.
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2589
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2590
        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.
2591
        """
2748.4.10 by Andrew Bennetts
Fix chunking serialisation to be current with the latest changes to the protocol, and improve the tests to make it harder to have them desynchronised.
2592
        stream = ['', 'chunk']
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
2593
        self.assertBodyStreamSerialisation(
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2594
            '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.
2595
        self.assertBodyStreamRoundTrips(stream)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2596
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2597
    def test_body_stream_error_serialistion(self):
2598
        stream = ['first chunk',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2599
                  _mod_request.FailedSmartServerResponse(
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2600
                      ('FailureName', 'failure arg'))]
2601
        expected_bytes = (
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2602
            '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.
2603
            'ERR\n' + 'b\nFailureName' + 'b\nfailure arg' +
2604
            'END\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2605
        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.
2606
        self.assertBodyStreamRoundTrips(stream)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2607
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2608
    def test__send_response_includes_failure_marker(self):
2609
        """FailedSmartServerResponse have 'failed\n' after the version."""
2610
        out_stream = StringIO()
2611
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2612
            None, out_stream.write)
2613
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2614
            _mod_request.FailedSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2615
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'failed\nx\n',
2616
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2617
2618
    def test__send_response_includes_success_marker(self):
2619
        """SuccessfulSmartServerResponse have 'success\n' after the version."""
2620
        out_stream = StringIO()
2621
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2622
            None, out_stream.write)
2623
        smart_protocol._send_response(
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
2624
            _mod_request.SuccessfulSmartServerResponse(('x',)))
2432.3.6 by Andrew Bennetts
Fix a couple of test failures introduced by the previous merge.
2625
        self.assertEqual(protocol.RESPONSE_VERSION_TWO + 'success\nx\n',
2626
                         out_stream.getvalue())
2432.4.6 by Robert Collins
Include success/failure feedback in SmartProtocolTwo responses to allow robust handling in the future.
2627
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2628
    def test__send_response_with_body_stream_sets_finished_reading(self):
2629
        smart_protocol = protocol.SmartServerRequestProtocolTwo(
2630
            None, lambda x: None)
2631
        self.assertEqual(1, smart_protocol.next_read_size())
2632
        smart_protocol._send_response(
3245.4.14 by Andrew Bennetts
Merge from bzr.dev (via loom thread).
2633
            _mod_request.SuccessfulSmartServerResponse(('x',), body_stream=[]))
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2634
        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.
2635
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2636
    def test_streamed_body_bytes(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2637
        body_header = 'chunked\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2638
        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.
2639
        body_terminator = "END\n"
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2640
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2641
                        "success\nok\n" + body_header + two_body_chunks +
2642
                        body_terminator)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2643
        input = StringIO(server_bytes)
2644
        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.
2645
        client_medium = medium.SmartSimplePipesClientMedium(
2646
            input, output, 'base')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
2647
        request = client_medium.get_request()
2648
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2649
        smart_protocol.call('foo')
2650
        smart_protocol.read_response_tuple(True)
2651
        stream = smart_protocol.read_streamed_body()
2652
        self.assertEqual(['1234', '567'], list(stream))
2653
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2654
    def test_read_streamed_body_error(self):
2655
        """When a stream is interrupted by an error..."""
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2656
        body_header = 'chunked\n'
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2657
        a_body_chunk = '4\naaaa'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2658
        err_signal = 'ERR\n'
2659
        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.
2660
        finish = 'END\n'
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
2661
        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.
2662
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
2663
                        "success\nok\n" + body)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2664
        input = StringIO(server_bytes)
2665
        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.
2666
        client_medium = medium.SmartSimplePipesClientMedium(
2667
            input, output, 'base')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2668
        smart_request = client_medium.get_request()
2669
        smart_protocol = protocol.SmartClientRequestProtocolTwo(smart_request)
2670
        smart_protocol.call('foo')
2671
        smart_protocol.read_response_tuple(True)
2672
        expected_chunks = [
2673
            'aaaa',
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
2674
            _mod_request.FailedSmartServerResponse(('error arg1', 'arg2'))]
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
2675
        stream = smart_protocol.read_streamed_body()
2676
        self.assertEqual(expected_chunks, list(stream))
2677
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2678
    def test_streamed_body_bytes_interrupted_connection(self):
2679
        body_header = 'chunked\n'
2680
        incomplete_body_chunk = "9999\nincomplete chunk"
2681
        server_bytes = (protocol.RESPONSE_VERSION_TWO +
2682
                        "success\nok\n" + body_header + incomplete_body_chunk)
2683
        input = StringIO(server_bytes)
2684
        output = StringIO()
2685
        client_medium = medium.SmartSimplePipesClientMedium(
2686
            input, output, 'base')
2687
        request = client_medium.get_request()
2688
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2689
        smart_protocol.call('foo')
2690
        smart_protocol.read_response_tuple(True)
2691
        stream = smart_protocol.read_streamed_body()
2692
        self.assertRaises(errors.ConnectionReset, stream.next)
2693
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2694
    def test_client_read_response_tuple_sets_response_status(self):
2695
        server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
2696
        input = StringIO(server_bytes)
2697
        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.
2698
        client_medium = medium.SmartSimplePipesClientMedium(
2699
            input, output, 'base')
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2700
        request = client_medium.get_request()
2701
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2702
        smart_protocol.call('foo')
2703
        smart_protocol.read_response_tuple(False)
2704
        self.assertEqual(True, smart_protocol.response_status)
2705
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2706
    def test_client_read_response_tuple_raises_UnknownSmartMethod(self):
2707
        """read_response_tuple raises UnknownSmartMethod if the response says
2708
        the server did not recognise the request.
2709
        """
2710
        server_bytes = (
2711
            protocol.RESPONSE_VERSION_TWO +
2712
            "failed\n" +
2713
            "error\x01Generic bzr smart protocol error: bad request 'foo'\n")
2714
        input = StringIO(server_bytes)
2715
        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.
2716
        client_medium = medium.SmartSimplePipesClientMedium(
2717
            input, output, 'base')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
2718
        request = client_medium.get_request()
2719
        smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
2720
        smart_protocol.call('foo')
2721
        self.assertRaises(
2722
            errors.UnknownSmartMethod, smart_protocol.read_response_tuple)
2723
        # The request has been finished.  There is no body to read, and
2724
        # attempts to read one will fail.
2725
        self.assertRaises(
2726
            errors.ReadingCompleted, smart_protocol.read_body_bytes)
2727
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2728
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.
2729
class TestSmartProtocolTwoSpecifics(
2730
        TestSmartProtocol, TestSmartProtocolTwoSpecificsMixin):
2731
    """Tests for aspects of smart protocol version two that are unique to
2732
    version two.
2733
2734
    Thus tests involving body streams and success/failure markers belong here.
2735
    """
2736
2737
    client_protocol_class = protocol.SmartClientRequestProtocolTwo
2738
    server_protocol_class = protocol.SmartServerRequestProtocolTwo
2739
2740
2741
class TestVersionOneFeaturesInProtocolThree(
2742
    TestSmartProtocol, CommonSmartProtocolTestMixin):
2743
    """Tests for version one smart protocol features as implemented by version
2744
    three.
2745
    """
2746
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2747
    request_encoder = protocol.ProtocolThreeRequester
2748
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2749
    # build_server_protocol_three is a function, so we can't set it as a class
2750
    # 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.
2751
    # method.  So we make server_protocol_class be a static method, rather than
2752
    # simply doing:
3245.4.4 by Andrew Bennetts
Fix a KnownFailure.
2753
    # "server_protocol_class = protocol.build_server_protocol_three".
3245.4.10 by Andrew Bennetts
Use a less ugly hack for TestVersionOneFeaturesInProtocolThree.server_protocol_class.
2754
    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.
2755
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2756
    def setUp(self):
2757
        super(TestVersionOneFeaturesInProtocolThree, self).setUp()
2758
        self.response_marker = protocol.MESSAGE_VERSION_THREE
2759
        self.request_marker = protocol.MESSAGE_VERSION_THREE
2760
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.
2761
    def test_construct_version_three_server_protocol(self):
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2762
        smart_protocol = protocol.ProtocolThreeDecoder(None)
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2763
        self.assertEqual('', smart_protocol.unused_data)
3649.5.5 by John Arbash Meinel
Fix the test suite.
2764
        self.assertEqual([], smart_protocol._in_buffer_list)
2765
        self.assertEqual(0, smart_protocol._in_buffer_len)
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
2766
        self.assertFalse(smart_protocol._has_dispatched)
3195.3.19 by Andrew Bennetts
Remove a stray pdb, fix a test.
2767
        # The protocol starts by expecting four bytes, a length prefix for the
2768
        # headers.
2769
        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.
2770
2771
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2772
class LoggingMessageHandler(object):
2773
2774
    def __init__(self):
2775
        self.event_log = []
2776
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2777
    def _log(self, *args):
2778
        self.event_log.append(args)
2779
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2780
    def headers_received(self, headers):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2781
        self._log('headers', headers)
2782
2783
    def protocol_error(self, exception):
2784
        self._log('protocol_error', exception)
2785
2786
    def byte_part_received(self, byte):
2787
        self._log('byte', byte)
2788
2789
    def bytes_part_received(self, bytes):
2790
        self._log('bytes', bytes)
2791
2792
    def structure_part_received(self, structure):
2793
        self._log('structure', structure)
2794
2795
    def end_received(self):
2796
        self._log('end')
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2797
2798
2799
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.
2800
    """Tests for v3 of the server-side protocol."""
2801
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
2802
    request_encoder = protocol.ProtocolThreeRequester
2803
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2804
    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.
2805
2806
    def test_trivial_request(self):
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2807
        """Smoke test for the simplest possible v3 request: empty headers, no
2808
        message parts.
3195.3.1 by Andrew Bennetts
Add TestProtocolTestCoverage.
2809
        """
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.
2810
        output = StringIO()
2811
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2812
        end = 'e'
2813
        request_bytes = headers + end
2814
        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.
2815
        smart_protocol.accept_bytes(request_bytes)
2816
        self.assertEqual(0, smart_protocol.next_read_size())
3245.4.21 by Andrew Bennetts
Remove 'excess_buffer' attribute and another crufty comment.
2817
        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.
2818
4515.1.1 by Andrew Bennetts
Fix bug in HPSS v3 decoder when receiving multiple lots of excess bytes.
2819
    def test_repeated_excess(self):
2820
        """Repeated calls to accept_bytes after the message end has been parsed
2821
        accumlates the bytes in the unused_data attribute.
2822
        """
2823
        output = StringIO()
2824
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
2825
        end = 'e'
2826
        request_bytes = headers + end
2827
        smart_protocol = self.server_protocol_class(LoggingMessageHandler())
2828
        smart_protocol.accept_bytes(request_bytes)
2829
        self.assertEqual('', smart_protocol.unused_data)
2830
        smart_protocol.accept_bytes('aaa')
2831
        self.assertEqual('aaa', smart_protocol.unused_data)
2832
        smart_protocol.accept_bytes('bbb')
2833
        self.assertEqual('aaabbb', smart_protocol.unused_data)
2834
        self.assertEqual(0, smart_protocol.next_read_size())
2835
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2836
    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.
2837
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2838
        message_handler = LoggingMessageHandler()
2839
        smart_protocol = self.server_protocol_class(message_handler)
2840
        smart_protocol.accept_bytes(headers)
2841
        # Clear the event log
2842
        del message_handler.event_log[:]
2843
        return smart_protocol, message_handler.event_log
2844
2845
    def test_decode_one_byte(self):
2846
        """The protocol can decode a 'one byte' message part."""
2847
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2848
        smart_protocol.accept_bytes('ox')
2849
        self.assertEqual([('byte', 'x')], event_log)
2850
2851
    def test_decode_bytes(self):
2852
        """The protocol can decode a 'bytes' message part."""
2853
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2854
        smart_protocol.accept_bytes(
2855
            'b' # message part kind
2856
            '\0\0\0\x07' # length prefix
2857
            'payload' # payload
2858
            )
2859
        self.assertEqual([('bytes', 'payload')], event_log)
2860
2861
    def test_decode_structure(self):
2862
        """The protocol can decode a 'structure' message part."""
2863
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2864
        smart_protocol.accept_bytes(
2865
            's' # message part kind
2866
            '\0\0\0\x07' # length prefix
2867
            'l3:ARGe' # ['ARG']
2868
            )
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
2869
        self.assertEqual([('structure', ('ARG',))], event_log)
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
2870
2871
    def test_decode_multiple_bytes(self):
2872
        """The protocol can decode a multiple 'bytes' message parts."""
2873
        smart_protocol, event_log = self.make_protocol_expecting_message_part()
2874
        smart_protocol.accept_bytes(
2875
            'b' # message part kind
2876
            '\0\0\0\x05' # length prefix
2877
            'first' # payload
2878
            'b' # message part kind
2879
            '\0\0\0\x06'
2880
            'second'
2881
            )
2882
        self.assertEqual(
2883
            [('bytes', 'first'), ('bytes', 'second')], event_log)
2884
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.
2885
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2886
class TestConventionalResponseHandlerBodyStream(tests.TestCase):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2887
3464.4.1 by Andrew Bennetts
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
2888
    def make_response_handler(self, response_bytes):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2889
        from bzrlib.smart.message import ConventionalResponseHandler
2890
        response_handler = ConventionalResponseHandler()
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
2891
        protocol_decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2892
        # put decoder in desired state (waiting for message parts)
2893
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2894
        output = StringIO()
2895
        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.
2896
            StringIO(response_bytes), output, 'base')
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2897
        medium_request = client_medium.get_request()
2898
        medium_request.finished_writing()
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
2899
        response_handler.setProtoAndMediumRequest(
2900
            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.
2901
        return response_handler
2902
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2903
    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.
2904
        response_handler = self.make_response_handler(interrupted_body_stream)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2905
        stream = response_handler.read_streamed_body()
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
2906
        self.assertEqual('aaa', stream.next())
2907
        self.assertEqual('bbb', stream.next())
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2908
        exc = self.assertRaises(errors.ErrorFromSmartServer, stream.next)
5677.2.7 by Martin
Store exception name after initial 'error' slot as suggested in review
2909
        self.assertEqual(('error', 'Exception', 'Boom!'), exc.error_tuple)
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
2910
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2911
    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.
2912
        interrupted_body_stream = (
2913
            'oS' # successful response
2914
            's\0\0\0\x02le' # empty args
2915
            'b\0\0\xff\xffincomplete chunk')
2916
        response_handler = self.make_response_handler(interrupted_body_stream)
2917
        stream = response_handler.read_streamed_body()
2918
        self.assertRaises(errors.ConnectionReset, stream.next)
2919
2920
    def test_read_body_bytes_interrupted_by_connection_lost(self):
2921
        interrupted_body_stream = (
2922
            'oS' # successful response
2923
            's\0\0\0\x02le' # empty args
2924
            'b\0\0\xff\xffincomplete chunk')
2925
        response_handler = self.make_response_handler(interrupted_body_stream)
2926
        self.assertRaises(
2927
            errors.ConnectionReset, response_handler.read_body_bytes)
2928
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2929
    def test_multiple_bytes_parts(self):
2930
        multiple_bytes_parts = (
2931
            'oS' # successful response
2932
            's\0\0\0\x02le' # empty args
2933
            'b\0\0\0\x0bSome bytes\n' # some bytes
2934
            'b\0\0\0\x0aMore bytes' # more bytes
2935
            'e' # message end
2936
            )
2937
        response_handler = self.make_response_handler(multiple_bytes_parts)
2938
        self.assertEqual(
2939
            'Some bytes\nMore bytes', response_handler.read_body_bytes())
2940
        response_handler = self.make_response_handler(multiple_bytes_parts)
2941
        self.assertEqual(
2942
            ['Some bytes\n', 'More bytes'],
2943
            list(response_handler.read_streamed_body()))
2944
2945
3923.5.6 by Andrew Bennetts
Fix a style nit.
2946
class FakeResponder(object):
2947
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2948
    response_sent = False
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_error(self, exc):
2951
        raise exc
3923.5.6 by Andrew Bennetts
Fix a style nit.
2952
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
2953
    def send_response(self, response):
2954
        pass
2955
2956
2957
class TestConventionalRequestHandlerBodyStream(tests.TestCase):
2958
    """Tests for ConventionalRequestHandler's handling of request bodies."""
2959
2960
    def make_request_handler(self, request_bytes):
2961
        """Make a ConventionalRequestHandler for the given bytes using test
2962
        doubles for the request_handler and the responder.
2963
        """
2964
        from bzrlib.smart.message import ConventionalRequestHandler
2965
        request_handler = InstrumentedRequestHandler()
2966
        request_handler.response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
3923.5.6 by Andrew Bennetts
Fix a style nit.
2967
        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.
2968
        message_handler = ConventionalRequestHandler(request_handler, responder)
2969
        protocol_decoder = protocol.ProtocolThreeDecoder(message_handler)
2970
        # put decoder in desired state (waiting for message parts)
2971
        protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
2972
        protocol_decoder.accept_bytes(request_bytes)
2973
        return request_handler
2974
2975
    def test_multiple_bytes_parts(self):
2976
        """Each bytes part triggers a call to the request_handler's
2977
        accept_body method.
2978
        """
2979
        multiple_bytes_parts = (
2980
            's\0\0\0\x07l3:fooe' # args
2981
            'b\0\0\0\x0bSome bytes\n' # some bytes
2982
            'b\0\0\0\x0aMore bytes' # more bytes
2983
            'e' # message end
2984
            )
2985
        request_handler = self.make_request_handler(multiple_bytes_parts)
2986
        accept_body_calls = [
2987
            call_info[1] for call_info in request_handler.calls
2988
            if call_info[0] == 'accept_body']
2989
        self.assertEqual(
2990
            ['Some bytes\n', 'More bytes'], accept_body_calls)
2991
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
2992
    def test_error_flag_after_body(self):
2993
        body_then_error = (
2994
            's\0\0\0\x07l3:fooe' # request args
2995
            'b\0\0\0\x0bSome bytes\n' # some bytes
2996
            'b\0\0\0\x0aMore bytes' # more bytes
2997
            'oE' # error flag
2998
            's\0\0\0\x07l3:bare' # error args
2999
            'e' # message end
3000
            )
3001
        request_handler = self.make_request_handler(body_then_error)
3002
        self.assertEqual(
3003
            [('post_body_error_received', ('bar',)), ('end_received',)],
3004
            request_handler.calls[-2:])
3005
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
3006
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.
3007
class TestMessageHandlerErrors(tests.TestCase):
3008
    """Tests for v3 that unrecognised (but well-formed) requests/responses are
3009
    still fully read off the wire, so that subsequent requests/responses on the
3010
    same medium can be decoded.
3011
    """
3012
3013
    def test_non_conventional_request(self):
3014
        """ConventionalRequestHandler (the default message handler on the
3015
        server side) will reject an unconventional message, but still consume
3016
        all the bytes of that message and signal when it has done so.
3017
3018
        This is what allows a server to continue to accept requests after the
3019
        client sends a completely unrecognised request.
3020
        """
3021
        # Define an invalid request (but one that is a well-formed message).
3022
        # This particular invalid request not only lacks the mandatory
3023
        # verb+args tuple, it has a single-byte part, which is forbidden.  In
3024
        # fact it has that part twice, to trigger multiple errors.
3025
        invalid_request = (
3026
            protocol.MESSAGE_VERSION_THREE +  # protocol version marker
3027
            '\0\0\0\x02de' + # empty headers
3028
            'oX' + # a single byte part: 'X'.  ConventionalRequestHandler will
3029
                   # error at this part.
3030
            'oX' + # and again.
3031
            'e' # end of message
3032
            )
3033
3034
        to_server = StringIO(invalid_request)
3035
        from_server = StringIO()
3036
        transport = memory.MemoryTransport('memory:///')
3037
        server = medium.SmartServerPipeStreamMedium(
6133.4.26 by John Arbash Meinel
get rid of the default timeout parameters.
3038
            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.
3039
        proto = server._build_protocol()
3040
        message_handler = proto.message_handler
3041
        server._serve_one_request(proto)
3042
        # All the bytes have been read from the medium...
3043
        self.assertEqual('', to_server.read())
3044
        # ...and the protocol decoder has consumed all the bytes, and has
3045
        # finished reading.
3046
        self.assertEqual('', proto.unused_data)
3047
        self.assertEqual(0, proto.next_read_size())
3048
3049
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.
3050
class InstrumentedRequestHandler(object):
3051
    """Test Double of SmartServerRequestHandler."""
3052
3053
    def __init__(self):
3054
        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.
3055
        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.
3056
3057
    def no_body_received(self):
3058
        self.calls.append(('no_body_received',))
3059
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).
3060
    def end_received(self):
3061
        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.
3062
        self.finished_reading = True
3063
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
3064
    def args_received(self, args):
3065
        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.
3066
3067
    def accept_body(self, bytes):
3068
        self.calls.append(('accept_body', bytes))
3069
3070
    def end_of_body(self):
3071
        self.calls.append(('end_of_body',))
3072
        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).
3073
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
3074
    def post_body_error_received(self, error_args):
3075
        self.calls.append(('post_body_error_received', error_args))
3076
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.
3077
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
3078
class StubRequest(object):
3079
3080
    def finished_reading(self):
3081
        pass
3082
3083
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
3084
class TestClientDecodingProtocolThree(TestSmartProtocol):
3085
    """Tests for v3 of the client-side protocol decoding."""
3086
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
3087
    def make_logging_response_decoder(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
3088
        """Make v3 response decoder using a test response handler."""
3089
        response_handler = LoggingMessageHandler()
3090
        decoder = protocol.ProtocolThreeDecoder(response_handler)
3091
        return decoder, response_handler
3092
3093
    def make_conventional_response_decoder(self):
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3094
        """Make v3 response decoder using a conventional response handler."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
3095
        response_handler = message.ConventionalResponseHandler()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3096
        decoder = protocol.ProtocolThreeDecoder(response_handler)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
3097
        response_handler.setProtoAndMediumRequest(decoder, StubRequest())
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3098
        return decoder, response_handler
3099
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
3100
    def test_trivial_response_decoding(self):
3101
        """Smoke test for the simplest possible v3 response: empty headers,
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3102
        status byte, empty args, no body.
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
3103
        """
3104
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3105
        response_status = 'oS' # success
3106
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
3107
        end = 'e' # end marker
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3108
        message_bytes = headers + response_status + args + end
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
3109
        decoder, response_handler = self.make_logging_response_decoder()
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3110
        decoder.accept_bytes(message_bytes)
3111
        # The protocol decoder has finished, and consumed all bytes
3245.4.22 by Andrew Bennetts
Uncomment TestClientDecodingProtocolThree.test_trivial_response_decoding.
3112
        self.assertEqual(0, decoder.next_read_size())
3113
        self.assertEqual('', decoder.unused_data)
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3114
        # The message handler has been invoked with all the parts of the
3115
        # trivial response: empty headers, status byte, no args, end.
3116
        self.assertEqual(
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
3117
            [('headers', {}), ('byte', 'S'), ('structure', ()), ('end',)],
3245.4.23 by Andrew Bennetts
Improve test_trivial_response_decoding slightly.
3118
            response_handler.event_log)
3195.3.5 by Andrew Bennetts
Start writing the client-side protocol logic for HPSS v3.
3119
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
3120
    def test_incomplete_message(self):
3121
        """A decoder will keep signalling that it needs more bytes via
3122
        next_read_size() != 0 until it has seen a complete message, regardless
3123
        which state it is in.
3124
        """
3125
        # Define a simple response that uses all possible message parts.
3126
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3127
        response_status = 'oS' # success
3128
        args = 's\0\0\0\x02le' # length-prefixed, bencoded empty list
3129
        body = 'b\0\0\0\x04BODY' # a body: 'BODY'
3130
        end = 'e' # end marker
3131
        simple_response = headers + response_status + args + body + end
3132
        # Feed the request to the decoder one byte at a time.
3133
        decoder, response_handler = self.make_logging_response_decoder()
3134
        for byte in simple_response:
3135
            self.assertNotEqual(0, decoder.next_read_size())
3136
            decoder.accept_bytes(byte)
3137
        # Now the response is complete
3138
        self.assertEqual(0, decoder.next_read_size())
3139
3140
    def test_read_response_tuple_raises_UnknownSmartMethod(self):
3141
        """read_response_tuple raises UnknownSmartMethod if the server replied
3142
        with 'UnknownMethod'.
3143
        """
3245.4.35 by Andrew Bennetts
Remove some commented out cruft, test (and fix) handling of an 'UnknownMethod' response.
3144
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3145
        response_status = 'oE' # error flag
3146
        # args: ('UnknownMethod', 'method-name')
3147
        args = 's\0\0\0\x20l13:UnknownMethod11:method-namee'
3148
        end = 'e' # end marker
3149
        message_bytes = headers + response_status + args + end
3150
        decoder, response_handler = self.make_conventional_response_decoder()
3151
        decoder.accept_bytes(message_bytes)
3152
        error = self.assertRaises(
3153
            errors.UnknownSmartMethod, response_handler.read_response_tuple)
3154
        self.assertEqual('method-name', error.verb)
3155
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
3156
    def test_read_response_tuple_error(self):
3157
        """If the response has an error, it is raised as an exception."""
3158
        headers = '\0\0\0\x02de'  # length-prefixed, bencoded empty dict
3159
        response_status = 'oE' # error
3160
        args = 's\0\0\0\x1al9:first arg10:second arge' # two args
3161
        end = 'e' # end marker
3162
        message_bytes = headers + response_status + args + end
3163
        decoder, response_handler = self.make_conventional_response_decoder()
3164
        decoder.accept_bytes(message_bytes)
3165
        error = self.assertRaises(
3166
            errors.ErrorFromSmartServer, response_handler.read_response_tuple)
3167
        self.assertEqual(('first arg', 'second arg'), error.error_tuple)
3168
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.
3169
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3170
class TestClientEncodingProtocolThree(TestSmartProtocol):
3171
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3172
    request_encoder = protocol.ProtocolThreeRequester
3173
    response_decoder = protocol.ProtocolThreeDecoder
3245.4.7 by Andrew Bennetts
Rename _ProtocolThreeBase to ProtocolThreeDecoder, remove SmartServerRequestProtocolThree.
3174
    server_protocol_class = protocol.ProtocolThreeDecoder
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3175
3176
    def make_client_encoder_and_output(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3177
        result = self.make_client_protocol_and_output()
3178
        requester, response_handler, output = result
3179
        return requester, output
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3180
3181
    def test_call_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3182
        """A smoke test for ProtocolThreeRequester.call.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3183
3184
        This test checks that a particular simple invocation of call emits the
3185
        correct bytes for that invocation.
3186
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3187
        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.
3188
        requester.set_headers({'header name': 'header value'})
3189
        requester.call('one arg')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3190
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3191
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3192
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
3193
            's\x00\x00\x00\x0bl7:one arge' # args
3194
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3195
            output.getvalue())
3196
3197
    def test_call_with_body_bytes_smoke_test(self):
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3198
        """A smoke test for ProtocolThreeRequester.call_with_body_bytes.
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3199
3200
        This test checks that a particular simple invocation of
3201
        call_with_body_bytes emits the correct bytes for that invocation.
3202
        """
3245.4.18 by Andrew Bennetts
Remove a bunch of cruft, especially the SmartClientRequestProtocolThree class.
3203
        requester, output = self.make_client_encoder_and_output()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3204
        requester.set_headers({'header name': 'header value'})
3205
        requester.call_with_body_bytes(('one arg',), 'body bytes')
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3206
        self.assertEquals(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3207
            'bzr message 3 (bzr 1.6)\n' # protocol version
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3208
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3195.3.16 by Andrew Bennetts
Update tests for revised v3 spec.
3209
            's\x00\x00\x00\x0bl7:one arge' # args
3210
            'b' # there is a prefixed body
3211
            '\x00\x00\x00\nbody bytes' # the prefixed body
3212
            'e', # end
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3213
            output.getvalue())
3214
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.
3215
    def test_call_writes_just_once(self):
3216
        """A bodyless request is written to the medium all at once."""
3217
        medium_request = StubMediumRequest()
3218
        encoder = protocol.ProtocolThreeRequester(medium_request)
3219
        encoder.call('arg1', 'arg2', 'arg3')
3220
        self.assertEqual(
3221
            ['accept_bytes', 'finished_writing'], medium_request.calls)
3222
3223
    def test_call_with_body_bytes_writes_just_once(self):
3224
        """A request with body bytes is written to the medium all at once."""
3225
        medium_request = StubMediumRequest()
3226
        encoder = protocol.ProtocolThreeRequester(medium_request)
3227
        encoder.call_with_body_bytes(('arg', 'arg'), 'body bytes')
3228
        self.assertEqual(
3229
            ['accept_bytes', 'finished_writing'], medium_request.calls)
3230
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
3231
    def test_call_with_body_stream_smoke_test(self):
3232
        """A smoke test for ProtocolThreeRequester.call_with_body_stream.
3233
3234
        This test checks that a particular simple invocation of
3235
        call_with_body_stream emits the correct bytes for that invocation.
3236
        """
3237
        requester, output = self.make_client_encoder_and_output()
3238
        requester.set_headers({'header name': 'header value'})
3239
        stream = ['chunk 1', 'chunk two']
3240
        requester.call_with_body_stream(('one arg',), stream)
3241
        self.assertEquals(
3242
            'bzr message 3 (bzr 1.6)\n' # protocol version
3243
            '\x00\x00\x00\x1fd11:header name12:header valuee' # headers
3244
            's\x00\x00\x00\x0bl7:one arge' # args
3245
            'b\x00\x00\x00\x07chunk 1' # a prefixed body chunk
3246
            'b\x00\x00\x00\x09chunk two' # a prefixed body chunk
3247
            'e', # end
3248
            output.getvalue())
3249
3250
    def test_call_with_body_stream_empty_stream(self):
3251
        """call_with_body_stream with an empty stream."""
3252
        requester, output = self.make_client_encoder_and_output()
3253
        requester.set_headers({})
3254
        stream = []
3255
        requester.call_with_body_stream(('one arg',), stream)
3256
        self.assertEquals(
3257
            'bzr message 3 (bzr 1.6)\n' # protocol version
3258
            '\x00\x00\x00\x02de' # headers
3259
            's\x00\x00\x00\x0bl7:one arge' # args
3260
            # no body chunks
3261
            'e', # end
3262
            output.getvalue())
3263
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
3264
    def test_call_with_body_stream_error(self):
3265
        """call_with_body_stream will abort the streamed body with an
3266
        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.
3267
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
3268
        The resulting request will still be a complete message.
3269
        """
3270
        requester, output = self.make_client_encoder_and_output()
3271
        requester.set_headers({})
3272
        def stream_that_fails():
3273
            yield 'aaa'
3274
            yield 'bbb'
3275
            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.
3276
        self.assertRaises(Exception, requester.call_with_body_stream,
3277
            ('one arg',), stream_that_fails())
3923.5.5 by Andrew Bennetts
Cleanly abort the request if an error occurs while iterating a body stream.
3278
        self.assertEquals(
3279
            'bzr message 3 (bzr 1.6)\n' # protocol version
3280
            '\x00\x00\x00\x02de' # headers
3281
            's\x00\x00\x00\x0bl7:one arge' # args
3282
            'b\x00\x00\x00\x03aaa' # body
3283
            'b\x00\x00\x00\x03bbb' # more body
3284
            'oE' # error flag
3285
            's\x00\x00\x00\x09l5:errore' # error args: ('error',)
3286
            'e', # end
3287
            output.getvalue())
3288
4797.93.1 by John Arbash Meinel
Implement retrying a request as long as we haven't started consuming the body stream.
3289
    def test_records_start_of_body_stream(self):
3290
        requester, output = self.make_client_encoder_and_output()
3291
        requester.set_headers({})
3292
        in_stream = [False]
3293
        def stream_checker():
3294
            self.assertTrue(requester.body_stream_started)
3295
            in_stream[0] = True
3296
            yield 'content'
3297
        flush_called = []
3298
        orig_flush = requester.flush
3299
        def tracked_flush():
3300
            flush_called.append(in_stream[0])
3301
            if in_stream[0]:
3302
                self.assertTrue(requester.body_stream_started)
3303
            else:
3304
                self.assertFalse(requester.body_stream_started)
3305
            return orig_flush()
3306
        requester.flush = tracked_flush
3307
        requester.call_with_body_stream(('one arg',), stream_checker())
3308
        self.assertEqual(
3309
            'bzr message 3 (bzr 1.6)\n' # protocol version
3310
            '\x00\x00\x00\x02de' # headers
3311
            's\x00\x00\x00\x0bl7:one arge' # args
3312
            'b\x00\x00\x00\x07content' # body
3313
            'e', output.getvalue())
3314
        self.assertEqual([False, True, True], flush_called)
3315
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.
3316
3317
class StubMediumRequest(object):
3318
    """A stub medium request that tracks the number of times accept_bytes is
3319
    called.
3320
    """
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
3321
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.
3322
    def __init__(self):
3323
        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.
3324
        self._medium = 'dummy medium'
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 accept_bytes(self, bytes):
3327
        self.calls.append('accept_bytes')
3441.3.3 by Andrew Bennetts
Fix PEP 8 nit.
3328
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.
3329
    def finished_writing(self):
3330
        self.calls.append('finished_writing')
3331
3195.3.14 by Andrew Bennetts
Add some tests for how the client encodes requests.
3332
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
3333
interrupted_body_stream = (
3334
    'oS' # status flag (success)
3335
    's\x00\x00\x00\x08l4:argse' # args struct ('args,')
3336
    'b\x00\x00\x00\x03aaa' # body part ('aaa')
3337
    'b\x00\x00\x00\x03bbb' # body part ('bbb')
3338
    'oE' # status flag (error)
5677.2.7 by Martin
Store exception name after initial 'error' slot as suggested in review
3339
    # err struct ('error', 'Exception', 'Boom!')
3340
    's\x00\x00\x00\x1bl5:error9:Exception5:Boom!e'
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
3341
    'e' # EOM
3342
    )
3343
3344
3245.4.37 by Andrew Bennetts
Add test for sending ProtocolThreeResponder.send_error(UnknownSmartMethod(...)).
3345
class TestResponseEncodingProtocolThree(tests.TestCase):
3346
3347
    def make_response_encoder(self):
3348
        out_stream = StringIO()
3349
        response_encoder = protocol.ProtocolThreeResponder(out_stream.write)
3350
        return response_encoder, out_stream
3351
3352
    def test_send_error_unknown_method(self):
3353
        encoder, out_stream = self.make_response_encoder()
3354
        encoder.send_error(errors.UnknownSmartMethod('method name'))
3355
        # Use assertEndsWith so that we don't compare the header, which varies
3356
        # by bzrlib.__version__.
3357
        self.assertEndsWith(
3358
            out_stream.getvalue(),
3359
            # error status
3360
            'oE' +
3361
            # tuple: 'UnknownMethod', 'method name'
3362
            's\x00\x00\x00\x20l13:UnknownMethod11:method namee'
3363
            # end of message
3364
            'e')
3365
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
3366
    def test_send_broken_body_stream(self):
3367
        encoder, out_stream = self.make_response_encoder()
3368
        encoder._headers = {}
3369
        def stream_that_fails():
3370
            yield 'aaa'
3371
            yield 'bbb'
3372
            raise Exception('Boom!')
3373
        response = _mod_request.SuccessfulSmartServerResponse(
3374
            ('args',), body_stream=stream_that_fails())
3375
        encoder.send_response(response)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
3376
        expected_response = (
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
3377
            'bzr message 3 (bzr 1.6)\n'  # protocol marker
3378
            '\x00\x00\x00\x02de' # headers dict (empty)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
3379
            + interrupted_body_stream)
3380
        self.assertEqual(expected_response, out_stream.getvalue())
4064.1.1 by Andrew Bennetts
Add TestResponseEncodingProtocolThree.test_send_broken_body_stream, and make it pass.
3381
3245.4.37 by Andrew Bennetts
Add test for sending ProtocolThreeResponder.send_error(UnknownSmartMethod(...)).
3382
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.
3383
class TestResponseEncoderBufferingProtocolThree(tests.TestCase):
3384
    """Tests for buffering of responses.
3385
3386
    We want to avoid doing many small writes when one would do, to avoid
3387
    unnecessary network overhead.
3388
    """
3389
3390
    def setUp(self):
4153.1.2 by Andrew Bennetts
Add missing TestCase.setUp upcalls.
3391
        tests.TestCase.setUp(self)
3441.3.1 by Andrew Bennetts
Buffer encoding of v3 messages to minimise write/send calls. Doubles the speed of pushing over TCP with 500ms latency loopback.
3392
        self.writes = []
3393
        self.responder = protocol.ProtocolThreeResponder(self.writes.append)
3394
3395
    def assertWriteCount(self, expected_count):
5283.5.2 by Martin Pool
Update tests for buffering of hpss output
3396
        # 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.
3397
        self.assertEqual(
3398
            expected_count, len(self.writes),
5283.5.2 by Martin Pool
Update tests for buffering of hpss output
3399
            "Too many writes: %d, expected %d" % (len(self.writes), expected_count))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3400
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.
3401
    def test_send_error_writes_just_once(self):
3402
        """An error response is written to the medium all at once."""
3403
        self.responder.send_error(Exception('An exception string.'))
3404
        self.assertWriteCount(1)
3405
3406
    def test_send_response_writes_just_once(self):
3407
        """A normal response with no body is written to the medium all at once.
3408
        """
3409
        response = _mod_request.SuccessfulSmartServerResponse(('arg', 'arg'))
3410
        self.responder.send_response(response)
3411
        self.assertWriteCount(1)
3412
3413
    def test_send_response_with_body_writes_just_once(self):
3414
        """A normal response with a monolithic body is written to the medium
3415
        all at once.
3416
        """
3417
        response = _mod_request.SuccessfulSmartServerResponse(
3418
            ('arg', 'arg'), body='body bytes')
3419
        self.responder.send_response(response)
3420
        self.assertWriteCount(1)
3421
4078.1.2 by Andrew Bennetts
Adjust write buffering tests for improved buffering.
3422
    def test_send_response_with_body_stream_buffers_writes(self):
3423
        """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.
3424
        # Construct a response with stream with 2 chunks in it.
3425
        response = _mod_request.SuccessfulSmartServerResponse(
3426
            ('arg', 'arg'), body_stream=['chunk1', 'chunk2'])
3427
        self.responder.send_response(response)
5283.5.2 by Martin Pool
Update tests for buffering of hpss output
3428
        # Per the discussion in bug 590638 we flush once after the header and
3429
        # then once after each chunk
3430
        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.
3431
3432
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
3433
class TestSmartClientUnicode(tests.TestCase):
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
3434
    """_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.
3435
3436
    Unicode arguments to call_with_body_bytes are not correct (remote method
3437
    names, arguments, and bodies must all be expressed as byte strings), but
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
3438
    _SmartClient should gracefully reject them, rather than getting into a
3439
    broken state that prevents future correct calls from working.  That is, it
3440
    should be possible to issue more requests on the medium afterwards, rather
3441
    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.
3442
    mysteriously fail with TooManyConcurrentRequests.
3443
    """
3444
3445
    def assertCallDoesNotBreakMedium(self, method, args, body):
3446
        """Call a medium with the given method, args and body, then assert that
3447
        the medium is left in a sane state, i.e. is capable of allowing further
3448
        requests.
3449
        """
3450
        input = StringIO("\n")
3451
        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.
3452
        client_medium = medium.SmartSimplePipesClientMedium(
3453
            input, output, 'ignored base')
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3454
        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.
3455
        self.assertRaises(TypeError,
3456
            smart_client.call_with_body_bytes, method, args, body)
3457
        self.assertEqual("", output.getvalue())
3458
        self.assertEqual(None, client_medium._current_request)
3459
3460
    def test_call_with_body_bytes_unicode_method(self):
3461
        self.assertCallDoesNotBreakMedium(u'method', ('args',), 'body')
3462
3463
    def test_call_with_body_bytes_unicode_args(self):
3464
        self.assertCallDoesNotBreakMedium('method', (u'args',), 'body')
2414.1.2 by Andrew Bennetts
Deal with review comments.
3465
        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.
3466
3467
    def test_call_with_body_bytes_unicode_body(self):
3468
        self.assertCallDoesNotBreakMedium('method', ('args',), u'body')
3469
3470
3453.4.4 by Andrew Bennetts
Small optimisation: don't bother trying RPCs from >= 1.6 if the server doesn't support protocol v3.
3471
class MockMedium(medium.SmartClientMedium):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3472
    """A mock medium that can be used to test _SmartClient.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3473
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3474
    It can be given a series of requests to expect (and responses it should
3475
    return for them).  It can also be told when the client is expected to
3476
    disconnect a medium.  Expectations must be satisfied in the order they are
3477
    given, or else an AssertionError will be raised.
3478
3479
    Typical use looks like::
3480
3481
        medium = MockMedium()
3482
        medium.expect_request(...)
3483
        medium.expect_request(...)
3484
        medium.expect_request(...)
3485
    """
3486
3487
    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.
3488
        super(MockMedium, self).__init__('dummy base')
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3489
        self._mock_request = _MockMediumRequest(self)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3490
        self._expected_events = []
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3491
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3492
    def expect_request(self, request_bytes, response_bytes,
3493
                       allow_partial_read=False):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3494
        """Expect 'request_bytes' to be sent, and reply with 'response_bytes'.
3495
3496
        No assumption is made about how many times accept_bytes should be
3497
        called to send the request.  Similarly, no assumption is made about how
3498
        many times read_bytes/read_line are called by protocol code to read a
3499
        response.  e.g.::
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3500
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3501
            request.accept_bytes('ab')
3502
            request.accept_bytes('cd')
3503
            request.finished_writing()
3504
3505
        and::
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3506
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3507
            request.accept_bytes('abcd')
3508
            request.finished_writing()
3509
3510
        Will both satisfy ``medium.expect_request('abcd', ...)``.  Thus tests
3511
        using this should not break due to irrelevant changes in protocol
3512
        implementations.
3513
3514
        :param allow_partial_read: if True, no assertion is raised if a
3515
            response is not fully read.  Setting this is useful when the client
3516
            is expected to disconnect without needing to read the complete
3517
            response.  Default is False.
3518
        """
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3519
        self._expected_events.append(('send request', request_bytes))
3520
        if allow_partial_read:
3521
            self._expected_events.append(
3522
                ('read response (partial)', response_bytes))
3523
        else:
3524
            self._expected_events.append(('read response', response_bytes))
3525
3526
    def expect_disconnect(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3527
        """Expect the client to call ``medium.disconnect()``."""
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3528
        self._expected_events.append('disconnect')
3529
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3530
    def _assertEvent(self, observed_event):
3531
        """Raise AssertionError unless observed_event matches the next expected
3532
        event.
3533
3534
        :seealso: expect_request
3535
        :seealso: expect_disconnect
3536
        """
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.
3537
        try:
3538
            expected_event = self._expected_events.pop(0)
3539
        except IndexError:
3540
            raise AssertionError(
3541
                'Mock medium observed event %r, but no more events expected'
3542
                % (observed_event,))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3543
        if expected_event[0] == 'read response (partial)':
3544
            if observed_event[0] != 'read response':
3545
                raise AssertionError(
3546
                    'Mock medium observed event %r, but expected event %r'
3547
                    % (observed_event, expected_event))
3548
        elif observed_event != expected_event:
3549
            raise AssertionError(
3550
                'Mock medium observed event %r, but expected event %r'
3551
                % (observed_event, expected_event))
3552
        if self._expected_events:
3553
            next_event = self._expected_events[0]
3554
            if next_event[0].startswith('read response'):
3555
                self._mock_request._response = next_event[1]
3556
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3557
    def get_request(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3558
        return self._mock_request
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3559
3560
    def disconnect(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3561
        if self._mock_request._read_bytes:
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3562
            self._assertEvent(('read response', self._mock_request._read_bytes))
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3563
            self._mock_request._read_bytes = ''
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3564
        self._assertEvent('disconnect')
3565
3566
3567
class _MockMediumRequest(object):
3568
    """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.
3569
3570
    def __init__(self, mock_medium):
3571
        self._medium = mock_medium
3572
        self._written_bytes = ''
3573
        self._read_bytes = ''
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3574
        self._response = None
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3575
3576
    def accept_bytes(self, bytes):
3577
        self._written_bytes += bytes
3578
3579
    def finished_writing(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3580
        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.
3581
        self._written_bytes = ''
3582
3583
    def finished_reading(self):
3245.4.45 by Andrew Bennetts
Improve documentation of MockMedium.
3584
        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.
3585
        self._read_bytes = ''
3586
3587
    def read_bytes(self, size):
3588
        resp = self._response
3589
        bytes, resp = resp[:size], resp[size:]
3590
        self._response = resp
3591
        self._read_bytes += bytes
3592
        return bytes
3593
3594
    def read_line(self):
3595
        resp = self._response
3596
        try:
3597
            line, resp = resp.split('\n', 1)
3598
            line += '\n'
3599
        except ValueError:
3600
            line, resp = resp, ''
3601
        self._response = resp
3602
        self._read_bytes += line
3603
        return line
3604
3605
3606
class Test_SmartClientVersionDetection(tests.TestCase):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3607
    """Tests for _SmartClient's automatic protocol version detection.
3608
3609
    On the first remote call, _SmartClient will keep retrying the request with
3610
    different protocol versions until it finds one that works.
3611
    """
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3612
3613
    def test_version_three_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3614
        """With a protocol 3 server, only one request is needed."""
3615
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3616
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3617
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
3618
        medium.expect_request(
3619
            message_start +
3620
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3621
            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.
3622
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3623
        # The call succeeded without raising any exceptions from the mock
3624
        # 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.
3625
        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.
3626
        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.
3627
        # Also, the v3 works then the server should be assumed to support RPCs
3628
        # introduced in 1.6.
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
3629
        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.
3630
3631
    def test_version_two_server(self):
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3632
        """If the server only speaks protocol 2, the client will first try
3633
        version 3, then fallback to protocol 2.
3634
3635
        Further, _SmartClient caches the detection, so future requests will all
3636
        use protocol 2 immediately.
3637
        """
3638
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3639
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3640
        # First the client should send a v3 request, but the server will reply
3641
        # with a v2 error.
3642
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3643
            '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.
3644
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3645
            'bzr response 2\nfailed\n\n')
3646
        # So then the client should disconnect to reset the connection, because
3647
        # the client needs to assume the server cannot read any further
3648
        # requests off the original connection.
3649
        medium.expect_disconnect()
3650
        # The client should then retry the original request in v2
3651
        medium.expect_request(
3652
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
3653
            'bzr response 2\nsuccess\nresponse value\n')
3654
        result = smart_client.call('method-name', 'arg 1', 'arg 2')
3655
        # The smart_client object will return the result of the successful
3656
        # query.
3657
        self.assertEqual(('response value',), result)
3658
3659
        # Now try another request, and this time the client will just use
3660
        # protocol 2.  (i.e. the autodetection won't be repeated)
3661
        medium.expect_request(
3662
            'bzr request 2\nanother-method\n',
3663
            'bzr response 2\nsuccess\nanother response\n')
3664
        result = smart_client.call('another-method')
3665
        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.
3666
        self.assertEqual([], medium._expected_events)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3667
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
        # Also, because v3 is not supported, the client medium should assume
3669
        # 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.
3670
        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.
3671
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3672
    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.
3673
        """If the server does not use any known (or at least supported)
3674
        protocol version, a SmartProtocolError is raised.
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3675
        """
3676
        medium = MockMedium()
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
3677
        smart_client = client._SmartClient(medium, headers={})
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
3678
        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.
3679
        # The client will try v3 and v2 before eventually giving up.
3680
        medium.expect_request(
3245.4.60 by Andrew Bennetts
Update the protocol v3 version string to say 'bzr 1.6'.
3681
            '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.
3682
            's\x00\x00\x00\x1el11:method-name5:arg 15:arg 2ee',
3683
            unknown_protocol_bytes)
3684
        medium.expect_disconnect()
3685
        medium.expect_request(
3686
            'bzr request 2\nmethod-name\x01arg 1\x01arg 2\n',
3687
            unknown_protocol_bytes)
3688
        medium.expect_disconnect()
3689
        self.assertRaises(
3690
            errors.SmartProtocolError,
3691
            smart_client.call, 'method-name', 'arg 1', 'arg 2')
3692
        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.
3693
3694
    def test_first_response_is_error(self):
3695
        """If the server replies with an error, then the version detection
3696
        should be complete.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3697
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
3698
        This test is very similar to test_version_two_server, but catches a bug
3699
        we had in the case where the first reply was an error response.
3700
        """
3701
        medium = MockMedium()
3702
        smart_client = client._SmartClient(medium, headers={})
3703
        message_start = protocol.MESSAGE_VERSION_THREE + '\x00\x00\x00\x02de'
3704
        # Issue a request that gets an error reply in a non-default protocol
3705
        # version.
3706
        medium.expect_request(
3707
            message_start +
3708
            's\x00\x00\x00\x10l11:method-nameee',
3709
            'bzr response 2\nfailed\n\n')
3710
        medium.expect_disconnect()
3711
        medium.expect_request(
3712
            'bzr request 2\nmethod-name\n',
3713
            'bzr response 2\nfailed\nFooBarError\n')
3714
        err = self.assertRaises(
3715
            errors.ErrorFromSmartServer,
3716
            smart_client.call, 'method-name')
3717
        self.assertEqual(('FooBarError',), err.error_tuple)
3718
        # Now the medium should have remembered the protocol version, so
3719
        # subsequent requests will use the remembered version immediately.
3720
        medium.expect_request(
3721
            'bzr request 2\nmethod-name\n',
3722
            'bzr response 2\nsuccess\nresponse value\n')
3723
        result = smart_client.call('method-name')
3724
        self.assertEqual(('response value',), result)
3725
        self.assertEqual([], medium._expected_events)
3726
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3727
3728
class Test_SmartClient(tests.TestCase):
3729
3730
    def test_call_default_headers(self):
3731
        """ProtocolThreeRequester.call by default sends a 'Software
3732
        version' header.
3733
        """
3431.3.4 by Andrew Bennetts
Revert now unnecessary test change from bzr.dev.
3734
        smart_client = client._SmartClient('dummy medium')
3245.4.55 by Andrew Bennetts
Test improvements suggested by John's review.
3735
        self.assertEqual(
3736
            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.
3737
        # XXX: need a test that smart_client._headers is passed to the request
3738
        # encoder.
3739
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3740
3741
class Test_SmartClientRequest(tests.TestCase):
3742
4797.85.34 by John Arbash Meinel
Start implementing retry during read.
3743
    def make_client_with_failing_medium(self, fail_at_write=True, response=''):
3744
        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.
3745
        output = StringIO()
4797.85.34 by John Arbash Meinel
Start implementing retry during read.
3746
        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.
3747
                    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
3748
        ssh_params = medium.SSHParams('a host', 'a port', 'a user', 'a pass')
3749
        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.
3750
        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.
3751
        return output, vendor, smart_client
3752
4797.85.34 by John Arbash Meinel
Start implementing retry during read.
3753
    def make_response(self, args, body=None, body_stream=None):
3754
        response_io = StringIO()
3755
        response = _mod_request.SuccessfulSmartServerResponse(args, body=body,
3756
            body_stream=body_stream)
3757
        responder = protocol.ProtocolThreeResponder(response_io.write)
3758
        responder.send_response(response)
3759
        return response_io.getvalue()
3760
3761
    def test__call_doesnt_retry_append(self):
3762
        response = self.make_response(('appended', '8'))
3763
        output, vendor, smart_client = self.make_client_with_failing_medium(
3764
            fail_at_write=False, response=response)
3765
        smart_request = client._SmartClientRequest(smart_client, 'append',
3766
            ('foo', ''), body='content\n')
3767
        self.assertRaises(errors.ConnectionReset, smart_request._call, 3)
3768
3769
    def test__call_retries_get_bytes(self):
3770
        response = self.make_response(('ok',), 'content\n')
3771
        output, vendor, smart_client = self.make_client_with_failing_medium(
3772
            fail_at_write=False, response=response)
3773
        smart_request = client._SmartClientRequest(smart_client, 'get',
3774
            ('foo',))
3775
        response, response_handler = smart_request._call(3)
3776
        self.assertEqual(('ok',), response)
3777
        self.assertEqual('content\n', response_handler.read_body_bytes())
3778
4797.85.37 by John Arbash Meinel
We should refuse to retry on read for -Dnoretry as well.
3779
    def test__call_noretry_get_bytes(self):
3780
        debug.debug_flags.add('noretry')
3781
        response = self.make_response(('ok',), 'content\n')
3782
        output, vendor, smart_client = self.make_client_with_failing_medium(
3783
            fail_at_write=False, response=response)
3784
        smart_request = client._SmartClientRequest(smart_client, 'get',
3785
            ('foo',))
3786
        self.assertRaises(errors.ConnectionReset, smart_request._call, 3)
3787
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3788
    def test__send_no_retry_pipes(self):
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3789
        client_read, server_write = create_file_pipes()
3790
        server_read, client_write = create_file_pipes()
3791
        client_medium = medium.SmartSimplePipesClientMedium(client_read,
3792
            client_write, base='/')
3793
        smart_client = client._SmartClient(client_medium)
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3794
        smart_request = client._SmartClientRequest(smart_client,
3795
            'hello', ())
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3796
        # Close the server side
3797
        server_read.close()
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3798
        encoder, response_handler = smart_request._construct_protocol(3)
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3799
        self.assertRaises(errors.ConnectionReset,
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3800
            smart_request._send_no_retry, encoder)
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3801
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3802
    def test__send_read_response_sockets(self):
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3803
        listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3804
        listen_sock.bind(('127.0.0.1', 0))
3805
        listen_sock.listen(1)
3806
        host, port = listen_sock.getsockname()
3807
        client_medium = medium.SmartTCPClientMedium(host, port, '/')
3808
        client_medium._ensure_connection()
3809
        smart_client = client._SmartClient(client_medium)
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3810
        smart_request = client._SmartClientRequest(smart_client, 'hello', ())
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3811
        # Accept the connection, but don't actually talk to the client.
3812
        server_sock, _ = listen_sock.accept()
3813
        server_sock.close()
3814
        # Sockets buffer and don't really notice that the server has closed the
3815
        # connection until we try to read again.
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3816
        handler = smart_request._send(3)
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3817
        self.assertRaises(errors.ConnectionReset,
3818
            handler.read_response_tuple, expect_body=False)
3819
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3820
    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.
3821
        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.
3822
        smart_request = client._SmartClientRequest(smart_client, 'hello', ())
3823
        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.
3824
        self.assertEqual('bzr message 3 (bzr 1.6)\n' # protocol
3825
                         '\x00\x00\x00\x02de'   # empty headers
3826
                         's\x00\x00\x00\tl5:helloee',
3827
                         output.getvalue())
4797.85.24 by John Arbash Meinel
Show that we try to retry the request if the first attempt fails.
3828
        self.assertEqual(
3829
            [('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3830
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3831
             ('close',),
3832
             ('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3833
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3834
            ],
3835
            vendor.calls)
3836
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3837
    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.
3838
        output, vendor, smart_client = self.make_client_with_failing_medium(
3839
            fail_at_write=False)
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3840
        smart_request = client._SmartClientRequest(smart_client, 'hello', ())
3841
        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.
3842
        self.assertEqual('bzr message 3 (bzr 1.6)\n' # protocol
3843
                         '\x00\x00\x00\x02de'   # empty headers
3844
                         's\x00\x00\x00\tl5:helloee',
3845
                         output.getvalue())
4797.85.25 by John Arbash Meinel
_send_request can't handle retrying during a read failure
3846
        self.assertEqual(
3847
            [('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3848
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3849
            ],
3850
            vendor.calls)
3851
        self.assertRaises(errors.ConnectionReset, handler.read_response_tuple)
4797.85.23 by John Arbash Meinel
Start direct testing of the reconnection attempts.
3852
4797.93.1 by John Arbash Meinel
Implement retrying a request as long as we haven't started consuming the body stream.
3853
    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.
3854
        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.
3855
        smart_request = client._SmartClientRequest(smart_client, 'hello', (),
3856
            body_stream=['a', 'b'])
3857
        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.
3858
        # We connect, get disconnected, and notice before consuming the stream,
3859
        # so we try again one time and succeed.
3860
        self.assertEqual(
3861
            [('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3862
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3863
             ('close',),
3864
             ('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3865
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3866
            ],
3867
            vendor.calls)
3868
        self.assertEqual('bzr message 3 (bzr 1.6)\n' # protocol
3869
                         '\x00\x00\x00\x02de'   # empty headers
3870
                         's\x00\x00\x00\tl5:helloe'
3871
                         'b\x00\x00\x00\x01a'
3872
                         'b\x00\x00\x00\x01b'
3873
                         'e',
3874
                         output.getvalue())
3875
3876
    def test__send_request_stops_if_body_started(self):
3877
        # We intentionally use the python StringIO so that we can subclass it.
3878
        from StringIO import StringIO
3879
        response = StringIO()
3880
3881
        class FailAfterFirstWrite(StringIO):
3882
            """Allow one 'write' call to pass, fail the rest"""
3883
            def __init__(self):
3884
                StringIO.__init__(self)
3885
                self._first = True
3886
3887
            def write(self, s):
3888
                if self._first:
3889
                    self._first = False
3890
                    return StringIO.write(self, s)
3891
                raise IOError(errno.EINVAL, 'invalid file handle')
3892
        output = FailAfterFirstWrite()
3893
3894
        vendor = FirstRejectedStringIOSSHVendor(response, output,
3895
            fail_at_write=False)
5050.78.6 by John Arbash Meinel
Merge in the stream retry code, and update for the slightly newer apis.
3896
        ssh_params = medium.SSHParams('a host', 'a port', 'a user', 'a pass')
3897
        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.
3898
        smart_client = client._SmartClient(client_medium, headers={})
4797.85.28 by John Arbash Meinel
Move all of the send logic into the _SmartClientRequest class.
3899
        smart_request = client._SmartClientRequest(smart_client, 'hello', (),
3900
            body_stream=['a', 'b'])
3901
        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.
3902
        # We connect, and manage to get to the point that we start consuming
3903
        # 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.
3904
        self.assertEqual(
3905
            [('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3906
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3907
             ('close',),
3908
            ],
3909
            vendor.calls)
4797.93.1 by John Arbash Meinel
Implement retrying a request as long as we haven't started consuming the body stream.
3910
        self.assertEqual('bzr message 3 (bzr 1.6)\n' # protocol
3911
                         '\x00\x00\x00\x02de'   # empty headers
3912
                         's\x00\x00\x00\tl5:helloe',
3913
                         output.getvalue())
4797.85.26 by John Arbash Meinel
If we get ConnectionReset and we are aborting the call reset the request.
3914
4797.91.5 by John Arbash Meinel
Add -Dnoretry as a way to disable all retrying code.
3915
    def test__send_disabled_retry(self):
3916
        debug.debug_flags.add('noretry')
3917
        output, vendor, smart_client = self.make_client_with_failing_medium()
3918
        smart_request = client._SmartClientRequest(smart_client, 'hello', ())
3919
        self.assertRaises(errors.ConnectionReset, smart_request._send, 3)
3920
        self.assertEqual(
3921
            [('connect_ssh', 'a user', 'a pass', 'a host', 'a port',
3922
              ['bzr', 'serve', '--inet', '--directory=/', '--allow-writes']),
3923
             ('close',),
3924
            ],
3925
            vendor.calls)
3926
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
3927
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3928
class LengthPrefixedBodyDecoder(tests.TestCase):
3929
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3930
    # 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.
3931
    # something similar to the ProtocolBase method.
3932
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3933
    def test_construct(self):
2018.5.3 by Andrew Bennetts
Split up more smart server code, this time into bzrlib/transport/smart/protocol.py
3934
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3935
        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.
3936
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3937
        self.assertEqual('', decoder.read_pending_data())
3938
        self.assertEqual('', decoder.unused_data)
3939
3940
    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
3941
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3942
        decoder.accept_bytes('')
3943
        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.
3944
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3945
        self.assertEqual('', decoder.read_pending_data())
3946
        self.assertEqual('', decoder.unused_data)
3947
        decoder.accept_bytes('7')
3948
        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.
3949
        self.assertEqual(6, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3950
        self.assertEqual('', decoder.read_pending_data())
3951
        self.assertEqual('', decoder.unused_data)
3952
        decoder.accept_bytes('\na')
3953
        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.
3954
        self.assertEqual(11, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3955
        self.assertEqual('a', decoder.read_pending_data())
3956
        self.assertEqual('', decoder.unused_data)
3957
        decoder.accept_bytes('bcdefgd')
3958
        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.
3959
        self.assertEqual(4, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3960
        self.assertEqual('bcdefg', decoder.read_pending_data())
3961
        self.assertEqual('', decoder.unused_data)
3962
        decoder.accept_bytes('one')
3963
        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.
3964
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3965
        self.assertEqual('', decoder.read_pending_data())
3966
        self.assertEqual('', decoder.unused_data)
3967
        decoder.accept_bytes('\nblarg')
3968
        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.
3969
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3970
        self.assertEqual('', decoder.read_pending_data())
3971
        self.assertEqual('blarg', decoder.unused_data)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3972
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3973
    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
3974
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3975
        decoder.accept_bytes('1\nadone\nunused')
3976
        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.
3977
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3978
        self.assertEqual('a', decoder.read_pending_data())
3979
        self.assertEqual('unused', decoder.unused_data)
3980
3981
    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
3982
        decoder = protocol.LengthPrefixedBodyDecoder()
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3983
        decoder.accept_bytes('1\na')
3984
        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.
3985
        self.assertEqual(5, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3986
        self.assertEqual('a', decoder.read_pending_data())
3987
        self.assertEqual('', decoder.unused_data)
3988
        decoder.accept_bytes('done\n')
3989
        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.
3990
        self.assertEqual(1, decoder.next_read_size())
2018.2.2 by Andrew Bennetts
Implement HTTP smart server.
3991
        self.assertEqual('', decoder.read_pending_data())
3992
        self.assertEqual('', decoder.unused_data)
3993
3994
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
3995
class TestChunkedBodyDecoder(tests.TestCase):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3996
    """Tests for ChunkedBodyDecoder.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
3997
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
3998
    This is the body decoder used for protocol version two.
3999
    """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4000
4001
    def test_construct(self):
4002
        decoder = protocol.ChunkedBodyDecoder()
4003
        self.assertFalse(decoder.finished_reading)
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4004
        self.assertEqual(8, decoder.next_read_size())
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4005
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4006
        self.assertEqual('', decoder.unused_data)
4007
4008
    def test_empty_content(self):
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4009
        """'chunked\nEND\n' is the complete encoding of a zero-length body.
4010
        """
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4011
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4012
        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.
4013
        decoder.accept_bytes('END\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4014
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4015
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4016
        self.assertEqual('', decoder.unused_data)
4017
4018
    def test_one_chunk(self):
4019
        """A body in a single chunk is decoded correctly."""
4020
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4021
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4022
        chunk_length = 'f\n'
4023
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4024
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4025
        decoder.accept_bytes(chunk_length + chunk_content + finish)
4026
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4027
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4028
        self.assertEqual('', decoder.unused_data)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
4029
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4030
    def test_incomplete_chunk(self):
4031
        """When there are less bytes in the chunk than declared by the length,
4032
        then we haven't finished reading yet.
4033
        """
4034
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4035
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4036
        chunk_length = '8\n'
4037
        three_bytes = '123'
4038
        decoder.accept_bytes(chunk_length + three_bytes)
4039
        self.assertFalse(decoder.finished_reading)
4040
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4041
            5 + 4, decoder.next_read_size(),
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4042
            "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.
4043
            "this chunk plus 4 (the length of the end-of-body marker: "
4044
            "'END\\n')")
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4045
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4046
4047
    def test_incomplete_length(self):
4048
        """A chunk length hasn't been read until a newline byte has been read.
4049
        """
4050
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4051
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4052
        decoder.accept_bytes('9')
4053
        self.assertEqual(
4054
            1, decoder.next_read_size(),
4055
            "The next_read_size hint should be 1, because we don't know the "
4056
            "length yet.")
4057
        decoder.accept_bytes('\n')
4058
        self.assertEqual(
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4059
            9 + 4, decoder.next_read_size(),
4060
            "The next_read_size hint should be the length of the chunk plus 4 "
4061
            "(the length of the end-of-body marker: 'END\\n')")
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4062
        self.assertFalse(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4063
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4064
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4065
    def test_two_chunks(self):
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4066
        """Content from multiple chunks is concatenated."""
4067
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4068
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4069
        chunk_one = '3\naaa'
4070
        chunk_two = '5\nbbbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4071
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4072
        decoder.accept_bytes(chunk_one + chunk_two + finish)
4073
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4074
        self.assertEqual('aaa', decoder.read_next_chunk())
4075
        self.assertEqual('bbbbb', decoder.read_next_chunk())
4076
        self.assertEqual(None, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4077
        self.assertEqual('', decoder.unused_data)
4078
4079
    def test_excess_bytes(self):
4080
        """Bytes after the chunked body are reported as unused bytes."""
4081
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4082
        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.
4083
        chunked_body = "5\naaaaaEND\n"
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4084
        excess_bytes = "excess bytes"
4085
        decoder.accept_bytes(chunked_body + excess_bytes)
4086
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4087
        self.assertEqual('aaaaa', decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4088
        self.assertEqual(excess_bytes, decoder.unused_data)
4089
        self.assertEqual(
4090
            1, decoder.next_read_size(),
4091
            "next_read_size hint should be 1 when finished_reading.")
4092
4093
    def test_multidigit_length(self):
4094
        """Lengths in the chunk prefixes can have multiple digits."""
4095
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4096
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4097
        length = 0x123
4098
        chunk_prefix = hex(length) + '\n'
4099
        chunk_bytes = 'z' * length
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4100
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4101
        decoder.accept_bytes(chunk_prefix + chunk_bytes + finish)
4102
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4103
        self.assertEqual(chunk_bytes, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4104
4105
    def test_byte_at_a_time(self):
4106
        """A complete body fed to the decoder one byte at a time should not
4107
        confuse the decoder.  That is, it should give the same result as if the
4108
        bytes had been received in one batch.
4109
4110
        This test is the same as test_one_chunk apart from the way accept_bytes
4111
        is called.
4112
        """
4113
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4114
        decoder.accept_bytes('chunked\n')
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4115
        chunk_length = 'f\n'
4116
        chunk_content = '123456789abcdef'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4117
        finish = 'END\n'
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4118
        for byte in (chunk_length + chunk_content + finish):
4119
            decoder.accept_bytes(byte)
4120
        self.assertTrue(decoder.finished_reading)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4121
        self.assertEqual(chunk_content, decoder.read_next_chunk())
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4122
        self.assertEqual('', decoder.unused_data)
4123
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4124
    def test_read_pending_data_resets(self):
4125
        """read_pending_data does not return the same bytes twice."""
4126
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4127
        decoder.accept_bytes('chunked\n')
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4128
        chunk_one = '3\naaa'
4129
        chunk_two = '3\nbbb'
2748.4.7 by Andrew Bennetts
Change the end-of-body marker to something clearer than a zero-length chunk.
4130
        finish = 'END\n'
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4131
        decoder.accept_bytes(chunk_one)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4132
        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.
4133
        decoder.accept_bytes(chunk_two)
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4134
        self.assertEqual('bbb', decoder.read_next_chunk())
4135
        self.assertEqual(None, decoder.read_next_chunk())
4136
4137
    def test_decode_error(self):
4138
        decoder = protocol.ChunkedBodyDecoder()
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4139
        decoder.accept_bytes('chunked\n')
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4140
        chunk_one = 'b\nfirst chunk'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
4141
        error_signal = 'ERR\n'
4142
        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.
4143
        finish = 'END\n'
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
4144
        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.
4145
        self.assertTrue(decoder.finished_reading)
4146
        self.assertEqual('first chunk', decoder.read_next_chunk())
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
4147
        expected_failure = _mod_request.FailedSmartServerResponse(
2748.4.6 by Andrew Bennetts
Use chunks for stream errors, rather than the response tuple format.
4148
            ('part1', 'part2'))
2748.4.5 by Andrew Bennetts
Allow an error to interrupt (and terminate) a streamed response body.
4149
        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.
4150
2748.4.16 by Andrew Bennetts
Tweaks suggested by review.
4151
    def test_bad_header(self):
4152
        """accept_bytes raises a SmartProtocolError if a chunked body does not
4153
        start with the right header.
4154
        """
4155
        decoder = protocol.ChunkedBodyDecoder()
4156
        self.assertRaises(
4157
            errors.SmartProtocolError, decoder.accept_bytes, 'bad header\n')
4158
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
4159
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4160
class TestSuccessfulSmartServerResponse(tests.TestCase):
4161
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4162
    def test_construct_no_body(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
4163
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4164
        self.assertEqual(('foo', 'bar'), response.args)
4165
        self.assertEqual(None, response.body)
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4166
4167
    def test_construct_with_body(self):
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
4168
        response = _mod_request.SuccessfulSmartServerResponse(('foo', 'bar'),
4169
                                                              'bytes')
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4170
        self.assertEqual(('foo', 'bar'), response.args)
4171
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
4172
        # repr(response) doesn't trigger exceptions.
4173
        repr(response)
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4174
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4175
    def test_construct_with_body_stream(self):
4176
        bytes_iterable = ['abc']
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
4177
        response = _mod_request.SuccessfulSmartServerResponse(
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4178
            ('foo', 'bar'), body_stream=bytes_iterable)
4179
        self.assertEqual(('foo', 'bar'), response.args)
4180
        self.assertEqual(bytes_iterable, response.body_stream)
4181
4182
    def test_construct_rejects_body_and_body_stream(self):
4183
        """'body' and 'body_stream' are mutually exclusive."""
4184
        self.assertRaises(
4185
            errors.BzrError,
2692.1.2 by Andrew Bennetts
Merge from bzr.dev.
4186
            _mod_request.SuccessfulSmartServerResponse, (), 'body', ['stream'])
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
4187
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4188
    def test_is_successful(self):
4189
        """is_successful should return True for SuccessfulSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
4190
        response = _mod_request.SuccessfulSmartServerResponse(('error',))
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4191
        self.assertEqual(True, response.is_successful())
4192
4193
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
4194
class TestFailedSmartServerResponse(tests.TestCase):
4195
4196
    def test_construct(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
4197
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
4198
        self.assertEqual(('foo', 'bar'), response.args)
4199
        self.assertEqual(None, response.body)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
4200
        response = _mod_request.FailedSmartServerResponse(('foo', 'bar'), 'bytes')
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
4201
        self.assertEqual(('foo', 'bar'), response.args)
4202
        self.assertEqual('bytes', response.body)
2781.2.1 by Andrew Bennetts
Fix SmartServerResponse.__repr__.
4203
        # repr(response) doesn't trigger exceptions.
4204
        repr(response)
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
4205
4206
    def test_is_successful(self):
4207
        """is_successful should return False for FailedSmartServerResponse."""
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
4208
        response = _mod_request.FailedSmartServerResponse(('error',))
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
4209
        self.assertEqual(False, response.is_successful())
4210
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
4211
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
4212
class FakeHTTPMedium(object):
4213
    def __init__(self):
4214
        self.written_request = None
4215
        self._current_request = None
2018.2.8 by Andrew Bennetts
Make HttpTransportBase.get_smart_client return self again.
4216
    def send_http_smart_request(self, bytes):
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
4217
        self.written_request = bytes
4218
        return None
4219
4220
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
4221
class HTTPTunnellingSmokeTest(tests.TestCase):
4222
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)
4223
    def setUp(self):
4224
        super(HTTPTunnellingSmokeTest, self).setUp()
4225
        # 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.
4226
        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)
4227
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
4228
    def test_smart_http_medium_request_accept_bytes(self):
4229
        medium = FakeHTTPMedium()
5010.2.9 by Vincent Ladeuil
Fix test_smart_transport.py imports.
4230
        request = http.SmartClientHTTPMediumRequest(medium)
2018.2.6 by Andrew Bennetts
HTTP client starting to work (pycurl for the moment).
4231
        request.accept_bytes('abc')
4232
        request.accept_bytes('def')
4233
        self.assertEqual(None, medium.written_request)
4234
        request.finished_writing()
4235
        self.assertEqual('abcdef', medium.written_request)
4236
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.
4237
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
4238
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.
4239
2208.4.3 by Andrew Bennetts
Let SmartHTTPTransport.clone('..') continue to POST to the cloned URL (unlike clone('child')).
4240
    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.
4241
        # 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')).
4242
        # requests for child URLs of that to the original URL.  i.e., we want to
4243
        # POST to "bzr+http://host/foo/.bzr/smart" and never something like
4244
        # "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.
4245
        # RemoteHTTPTransport remembers the initial URL, and adjusts the
4246
        # relpaths it sends in smart requests accordingly.
2208.4.4 by Andrew Bennetts
Merge bzr.dev.
4247
        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.
4248
        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')).
4249
        self.assertEqual(base_transport._http_transport,
4250
                         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.
4251
        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.
4252
        self.assertEqual(
4253
            'child_dir/',
4254
            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')).
4255
2466.3.1 by Andrew Bennetts
Normalise URLs in RemoteHTTPTransport before doing URL calculations to fix bad results.
4256
    def test_remote_path_unnormal_base(self):
4257
        # If the transport's base isn't normalised, the _remote_path should
4258
        # still be calculated correctly.
4259
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
4260
        self.assertEqual('c', base_transport._remote_path('c'))
4261
4262
    def test_clone_unnormal_base(self):
4263
        # If the transport's base isn't normalised, cloned transports should
4264
        # still work correctly.
4265
        base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
4266
        new_transport = base_transport.clone('c')
6061.1.9 by Martin Packman
Unbreak test_clone_unnormal_base by not asserting url keeps tilde escaped
4267
        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.
4268
        self.assertEqual(
4269
            'c/',
4270
            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.
4271
3878.4.6 by Vincent Ladeuil
Fix bug #270863 by preserving 'bzr+http[s]' decorator.
4272
    def test__redirect_to(self):
4273
        t = remote.RemoteHTTPTransport('bzr+http://www.example.com/foo')
4274
        r = t._redirected_to('http://www.example.com/foo',
4275
                             'http://www.example.com/bar')
4276
        self.assertEquals(type(r), type(t))
4277
4278
    def test__redirect_sibling_protocol(self):
4279
        t = remote.RemoteHTTPTransport('bzr+http://www.example.com/foo')
4280
        r = t._redirected_to('http://www.example.com/foo',
4281
                             'https://www.example.com/bar')
4282
        self.assertEquals(type(r), type(t))
4283
        self.assertStartsWith(r.base, 'bzr+https')
4284
4285
    def test__redirect_to_with_user(self):
4286
        t = remote.RemoteHTTPTransport('bzr+http://joe@www.example.com/foo')
4287
        r = t._redirected_to('http://www.example.com/foo',
4288
                             'http://www.example.com/bar')
4289
        self.assertEquals(type(r), type(t))
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
4290
        self.assertEquals('joe', t._parsed_url.user)
4291
        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.
4292
4293
    def test_redirected_to_same_host_different_protocol(self):
4294
        t = remote.RemoteHTTPTransport('bzr+http://joe@www.example.com/foo')
4295
        r = t._redirected_to('http://www.example.com/foo',
4296
                             'ftp://www.example.com/foo')
4297
        self.assertNotEquals(type(r), type(t))
4298
4299