~bzr-pqm/bzr/bzr.dev

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