bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
1 |
# Copyright (C) 2006 Canonical Ltd
|
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
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
17 |
"""Tests for smart transport"""
|
|
18 |
||
19 |
# all of this deals with byte strings so this is safe
|
|
20 |
from cStringIO import StringIO |
|
21 |
import subprocess |
|
22 |
import sys |
|
23 |
||
24 |
import bzrlib |
|
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
25 |
from bzrlib import ( |
26 |
bzrdir, |
|
27 |
errors, |
|
28 |
tests, |
|
|
2049.1.1
by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes. |
29 |
urlutils, |
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
30 |
)
|
31 |
from bzrlib.transport import ( |
|
32 |
get_transport, |
|
33 |
local, |
|
34 |
memory, |
|
35 |
smart, |
|
36 |
)
|
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
37 |
|
38 |
||
39 |
class SmartClientTests(tests.TestCase): |
|
40 |
||
41 |
def test_construct_smart_stream_client(self): |
|
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
42 |
# make a new client; this really wants a connector function that returns
|
43 |
# two fifos or sockets but the constructor should not do any IO
|
|
44 |
client = smart.SmartStreamClient(None) |
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
45 |
|
46 |
||
47 |
class TCPClientTests(tests.TestCaseWithTransport): |
|
48 |
||
49 |
def setUp(self): |
|
50 |
super(TCPClientTests, self).setUp() |
|
51 |
# We're allowed to set the transport class here, so that we don't use
|
|
52 |
# the default or a parameterized class, but rather use the
|
|
53 |
# TestCaseWithTransport infrastructure to set up a smart server and
|
|
54 |
# transport.
|
|
55 |
self.transport_server = smart.SmartTCPServer_for_testing |
|
56 |
||
57 |
def test_plausible_url(self): |
|
58 |
self.assert_(self.get_url().startswith('bzr://')) |
|
59 |
||
60 |
def test_probe_transport(self): |
|
61 |
t = self.get_transport() |
|
62 |
self.assertIsInstance(t, smart.SmartTransport) |
|
63 |
||
64 |
def test_get_client_from_transport(self): |
|
65 |
t = self.get_transport() |
|
66 |
client = t.get_smart_client() |
|
67 |
self.assertIsInstance(client, smart.SmartStreamClient) |
|
68 |
||
69 |
||
70 |
class BasicSmartTests(tests.TestCase): |
|
71 |
||
72 |
def test_smart_query_version(self): |
|
73 |
"""Feed a canned query version to a server""" |
|
74 |
to_server = StringIO('hello\n') |
|
75 |
from_server = StringIO() |
|
|
2049.1.1
by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes. |
76 |
server = smart.SmartStreamServer(to_server, from_server, |
77 |
local.LocalTransport(urlutils.local_path_to_url('/'))) |
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
78 |
server._serve_one_request() |
79 |
self.assertEqual('ok\0011\n', |
|
80 |
from_server.getvalue()) |
|
81 |
||
82 |
def test_canned_get_response(self): |
|
83 |
transport = memory.MemoryTransport('memory:///') |
|
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
84 |
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 |
85 |
to_server = StringIO('get\001./testfile\n') |
86 |
from_server = StringIO() |
|
87 |
server = smart.SmartStreamServer(to_server, from_server, transport) |
|
88 |
server._serve_one_request() |
|
89 |
self.assertEqual('ok\n' |
|
90 |
'17\n' |
|
91 |
'contents\nof\nfile\n' |
|
92 |
'done\n', |
|
93 |
from_server.getvalue()) |
|
94 |
||
95 |
def test_get_error_unexpected(self): |
|
96 |
"""Error reported by server with no specific representation""" |
|
97 |
class FlakyTransport(object): |
|
|
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. |
98 |
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 |
99 |
raise Exception("some random exception from inside server") |
100 |
server = smart.SmartTCPServer(backing_transport=FlakyTransport()) |
|
101 |
server.start_background_thread() |
|
102 |
try: |
|
103 |
transport = smart.SmartTCPTransport(server.get_url()) |
|
104 |
try: |
|
105 |
transport.get('something') |
|
106 |
except errors.TransportError, e: |
|
107 |
self.assertContainsRe(str(e), 'some random exception') |
|
108 |
else: |
|
109 |
self.fail("get did not raise expected error") |
|
110 |
finally: |
|
111 |
server.stop_background_thread() |
|
112 |
||
113 |
def test_server_subprocess(self): |
|
114 |
"""Talk to a server started as a subprocess |
|
115 |
|
|
116 |
This is similar to running it over ssh, except that it runs in the same machine
|
|
117 |
without ssh intermediating.
|
|
118 |
"""
|
|
119 |
args = [sys.executable, sys.argv[0], 'serve', '--inet'] |
|
|
2049.1.1
by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes. |
120 |
do_close_fds = True |
121 |
if sys.platform == 'win32': |
|
122 |
do_close_fds = False |
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
123 |
child = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, |
|
2049.1.1
by Lukáš Lalinský
Windows-speficic smart server transport selftest fixes. |
124 |
close_fds=do_close_fds, universal_newlines=True) |
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
125 |
conn = smart.SmartStreamClient(lambda: (child.stdout, child.stdin)) |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
126 |
conn.query_version() |
127 |
conn.query_version() |
|
128 |
conn.disconnect() |
|
129 |
returncode = child.wait() |
|
130 |
self.assertEquals(0, returncode) |
|
131 |
||
132 |
||
133 |
class SmartTCPTests(tests.TestCase): |
|
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
134 |
"""Tests for connection/end to end behaviour using the TCP server. |
135 |
||
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
136 |
All of these tests are run with a server running on another thread serving
|
137 |
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`. |
138 |
|
139 |
the server is obtained by calling self.setUpServer(readonly=False).
|
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
140 |
"""
|
141 |
||
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
142 |
def setUpServer(self, readonly=False): |
143 |
"""Setup the server. |
|
144 |
||
145 |
:param readonly: Create a readonly server.
|
|
146 |
"""
|
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
147 |
self.backing_transport = memory.MemoryTransport() |
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
148 |
if readonly: |
149 |
self.real_backing_transport = self.backing_transport |
|
150 |
self.backing_transport = get_transport("readonly+" + self.backing_transport.abspath('.')) |
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
151 |
self.server = smart.SmartTCPServer(self.backing_transport) |
152 |
self.server.start_background_thread() |
|
153 |
self.transport = smart.SmartTCPTransport(self.server.get_url()) |
|
154 |
||
155 |
def tearDown(self): |
|
156 |
if getattr(self, 'transport', None): |
|
157 |
self.transport.disconnect() |
|
158 |
if getattr(self, 'server', None): |
|
159 |
self.server.stop_background_thread() |
|
160 |
super(SmartTCPTests, self).tearDown() |
|
161 |
||
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
162 |
|
163 |
class WritableEndToEndTests(SmartTCPTests): |
|
164 |
"""Client to server tests that require a writable transport.""" |
|
165 |
||
166 |
def setUp(self): |
|
167 |
super(WritableEndToEndTests, self).setUp() |
|
168 |
self.setUpServer() |
|
169 |
||
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
170 |
def test_start_tcp_server(self): |
171 |
url = self.server.get_url() |
|
172 |
self.assertContainsRe(url, r'^bzr://127\.0\.0\.1:[0-9]{2,}/') |
|
173 |
||
174 |
def test_smart_transport_has(self): |
|
175 |
"""Checking for file existence over smart.""" |
|
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
176 |
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 |
177 |
self.assertTrue(self.transport.has("foo")) |
178 |
self.assertFalse(self.transport.has("non-foo")) |
|
179 |
||
180 |
def test_smart_transport_get(self): |
|
181 |
"""Read back a file over smart.""" |
|
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
182 |
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 |
183 |
fp = self.transport.get("foo") |
184 |
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`. |
185 |
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
186 |
def test_get_error_enoent(self): |
187 |
"""Error reported from server getting nonexistent file.""" |
|
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
188 |
# The path in a raised NoSuchFile exception should be the precise path
|
189 |
# asked for by the client. This gives meaningful and unsurprising errors
|
|
190 |
# for users.
|
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
191 |
try: |
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
192 |
self.transport.get('not%20a%20file') |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
193 |
except errors.NoSuchFile, e: |
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
194 |
self.assertEqual('not%20a%20file', e.path) |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
195 |
else: |
196 |
self.fail("get did not raise expected error") |
|
197 |
||
198 |
def test_simple_clone_conn(self): |
|
199 |
"""Test that cloning reuses the same connection.""" |
|
200 |
# we create a real connection not a loopback one, but it will use the
|
|
201 |
# same server and pipes
|
|
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
202 |
conn2 = self.transport.clone('.') |
|
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) |
203 |
self.assertTrue(self.transport._client is conn2._client) |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
204 |
|
|
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) |
205 |
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 |
206 |
self.assertEquals('/foo/bar', |
207 |
self.transport._remote_path('foo/bar')) |
|
208 |
||
209 |
def test_clone_changes_base(self): |
|
210 |
"""Cloning transport produces one with a new base location""" |
|
211 |
conn2 = self.transport.clone('subdir') |
|
212 |
self.assertEquals(self.transport.base + 'subdir/', |
|
213 |
conn2.base) |
|
214 |
||
215 |
def test_open_dir(self): |
|
216 |
"""Test changing directory""" |
|
217 |
transport = self.transport |
|
218 |
self.backing_transport.mkdir('toffee') |
|
219 |
self.backing_transport.mkdir('toffee/apple') |
|
220 |
self.assertEquals('/toffee', transport._remote_path('toffee')) |
|
|
1910.19.13
by Andrew Bennetts
Address various review comments. |
221 |
toffee_trans = transport.clone('toffee') |
222 |
# Check that each transport has only the contents of its directory
|
|
223 |
# directly visible. If state was being held in the wrong object, it's
|
|
224 |
# conceivable that cloning a transport would alter the state of the
|
|
225 |
# cloned-from transport.
|
|
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
226 |
self.assertTrue(transport.has('toffee')) |
|
1910.19.13
by Andrew Bennetts
Address various review comments. |
227 |
self.assertFalse(toffee_trans.has('toffee')) |
228 |
self.assertFalse(transport.has('apple')) |
|
229 |
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 |
230 |
|
231 |
def test_open_bzrdir(self): |
|
232 |
"""Open an existing bzrdir over smart transport""" |
|
233 |
transport = self.transport |
|
234 |
t = self.backing_transport |
|
235 |
bzrdir.BzrDirFormat.get_default_format().initialize_on_transport(t) |
|
236 |
result_dir = bzrdir.BzrDir.open_containing_from_transport(transport) |
|
237 |
||
238 |
||
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
239 |
class ReadOnlyEndToEndTests(SmartTCPTests): |
240 |
"""Tests from the client to the server using a readonly backing transport.""" |
|
241 |
||
242 |
def test_mkdir_error_readonly(self): |
|
243 |
"""TransportNotPossible should be preserved from the backing transport.""" |
|
244 |
self.setUpServer(readonly=True) |
|
245 |
self.assertRaises(errors.TransportNotPossible, self.transport.mkdir, |
|
246 |
'foo') |
|
247 |
||
248 |
||
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
249 |
class SmartServerTests(tests.TestCaseWithTransport): |
250 |
"""Test that call directly into the server logic, bypassing the network.""" |
|
251 |
||
252 |
def test_hello(self): |
|
253 |
server = smart.SmartServer(None) |
|
254 |
response = server.dispatch_command('hello', ()) |
|
255 |
self.assertEqual(('ok', '1'), response.args) |
|
256 |
self.assertEqual(None, response.body) |
|
257 |
||
258 |
def test_get_bundle(self): |
|
259 |
from bzrlib.bundle import serializer |
|
260 |
wt = self.make_branch_and_tree('.') |
|
|
1910.19.13
by Andrew Bennetts
Address various review comments. |
261 |
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 |
262 |
wt.add('hello') |
|
1910.19.13
by Andrew Bennetts
Address various review comments. |
263 |
rev_id = wt.commit('add hello') |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
264 |
|
265 |
server = smart.SmartServer(self.get_transport()) |
|
|
1910.19.13
by Andrew Bennetts
Address various review comments. |
266 |
response = server.dispatch_command('get_bundle', ('.', rev_id)) |
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
267 |
bundle = serializer.read_bundle(StringIO(response.body)) |
268 |
||
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
269 |
def test_readonly_exception_becomes_transport_not_possible(self): |
270 |
"""The response for a read-only error is ('ReadOnlyError').""" |
|
271 |
server = smart.SmartServer(self.get_readonly_transport()) |
|
272 |
# send a mkdir for foo, with no explicit mode - should fail.
|
|
273 |
response = server.dispatch_command('mkdir', ('foo', '')) |
|
274 |
# and the failure should be an explicit ReadOnlyError
|
|
275 |
self.assertEqual(("ReadOnlyError", ), response.args) |
|
276 |
# XXX: TODO: test that other TransportNotPossible errors are
|
|
277 |
# presented as TransportNotPossible - not possible to do that
|
|
278 |
# until I figure out how to trigger that relatively cleanly via
|
|
279 |
# the api. RBC 20060918
|
|
280 |
||
|
1910.19.3
by Andrew Bennetts
Add SSH support. |
281 |
|
282 |
class SmartTransportRegistration(tests.TestCase): |
|
283 |
||
284 |
def test_registration(self): |
|
285 |
t = get_transport('bzr+ssh://example.com/path') |
|
286 |
self.assertIsInstance(t, smart.SmartSSHTransport) |
|
287 |
self.assertEqual('example.com', t._host) |
|
288 |
||
289 |
||
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
290 |
class FakeClient(smart.SmartStreamClient): |
291 |
"""Emulate a client for testing a transport's use of the client.""" |
|
292 |
||
293 |
def __init__(self): |
|
294 |
smart.SmartStreamClient.__init__(self, None) |
|
295 |
self._calls = [] |
|
296 |
||
297 |
def _call(self, *args): |
|
298 |
self._calls.append(('_call', args)) |
|
299 |
return ('ok', ) |
|
300 |
||
301 |
def _recv_bulk(self): |
|
302 |
return 'bar' |
|
303 |
||
304 |
||
305 |
class TestSmartTransport(tests.TestCase): |
|
306 |
||
307 |
def test_use_connection_factory(self): |
|
308 |
# We want to be able to pass a client as a parameter to SmartTransport.
|
|
309 |
client = FakeClient() |
|
310 |
transport = smart.SmartTransport('bzr://localhost/', client=client) |
|
311 |
||
312 |
# We want to make sure the client is used when the first remote
|
|
313 |
# method is called. No method should have been called yet.
|
|
314 |
self.assertEqual([], client._calls) |
|
315 |
||
316 |
# Now call a method that should result in a single request.
|
|
317 |
self.assertEqual('bar', transport.get_bytes('foo')) |
|
318 |
# The only call to _call should have been to get /foo.
|
|
319 |
self.assertEqual([('_call', ('get', '/foo'))], client._calls) |
|
320 |
||
|
2020.1.1
by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`. |
321 |
def test__translate_error_readonly(self): |
322 |
"""Sending a ReadOnlyError to _translate_error raises TransportNotPossible.""" |
|
323 |
client = FakeClient() |
|
324 |
transport = smart.SmartTransport('bzr://localhost/', client=client) |
|
325 |
self.assertRaises(errors.TransportNotPossible, |
|
326 |
transport._translate_error, ("ReadOnlyError", )) |
|
327 |
||
|
1910.19.11
by Andrew Bennetts
General code cleanup based on review comments and other observations. |
328 |
|
|
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. |
329 |
class InstrumentedClient(smart.SmartStreamClient): |
330 |
"""A smart client whose writes are stored to a supplied list.""" |
|
331 |
||
332 |
def __init__(self, write_output_list): |
|
333 |
smart.SmartStreamClient.__init__(self, None) |
|
334 |
self._write_output_list = write_output_list |
|
335 |
||
336 |
def _ensure_connection(self): |
|
337 |
"""We are never strictly connected.""" |
|
338 |
||
339 |
def _write_and_flush(self, bytes): |
|
340 |
self._write_output_list.append(bytes) |
|
341 |
||
342 |
||
343 |
class InstrumentedServerProtocol(smart.SmartStreamServer): |
|
344 |
"""A smart server which is backed by memory and saves its write requests.""" |
|
345 |
||
346 |
def __init__(self, write_output_list): |
|
347 |
smart.SmartStreamServer.__init__(self, None, None, |
|
348 |
memory.MemoryTransport()) |
|
349 |
self._write_output_list = write_output_list |
|
350 |
||
351 |
def _write_and_flush(self, bytes): |
|
352 |
self._write_output_list.append(bytes) |
|
353 |
||
354 |
||
355 |
class TestSmartProtocol(tests.TestCase): |
|
356 |
"""Tests for the smart protocol. |
|
357 |
||
358 |
Each test case gets a smart_server and smart_client created during setUp().
|
|
359 |
||
360 |
It is planned that the client can be called with self.call_client() giving
|
|
361 |
it an expected server response, which will be fed into it when it tries to
|
|
362 |
read. Likewise, self.call_server will call a servers method with a canned
|
|
363 |
serialised client request. Output done by the client or server for these
|
|
364 |
calls will be captured to self.to_server and self.to_client. Each element
|
|
365 |
in the list is a write call from the client or server respectively.
|
|
366 |
"""
|
|
367 |
||
368 |
def setUp(self): |
|
369 |
super(TestSmartProtocol, self).setUp() |
|
370 |
self.to_server = [] |
|
371 |
self.to_client = [] |
|
372 |
self.smart_client = InstrumentedClient(self.to_server) |
|
373 |
self.smart_server = InstrumentedServerProtocol(self.to_client) |
|
374 |
||
375 |
def assertOffsetSerialisation(self, expected_offsets, expected_serialised, |
|
376 |
client, server_protocol): |
|
377 |
"""Check that smart (de)serialises offsets as expected. |
|
378 |
|
|
379 |
We check both serialisation and deserialisation at the same time
|
|
380 |
to ensure that the round tripping cannot skew: both directions should
|
|
381 |
be as expected.
|
|
382 |
|
|
383 |
:param expected_offsets: a readv offset list.
|
|
384 |
:param expected_seralised: an expected serial form of the offsets.
|
|
385 |
:param server: a SmartServer instance.
|
|
386 |
"""
|
|
387 |
offsets = server_protocol.smart_server._deserialise_offsets( |
|
388 |
expected_serialised) |
|
389 |
self.assertEqual(expected_offsets, offsets) |
|
390 |
serialised = client._serialise_offsets(offsets) |
|
391 |
self.assertEqual(expected_serialised, serialised) |
|
392 |
||
393 |
def test_server_offset_serialisation(self): |
|
394 |
"""The Smart protocol serialises offsets as a comma and \n string. |
|
395 |
||
396 |
We check a number of boundary cases are as expected: empty, one offset,
|
|
397 |
one with the order of reads not increasing (an out of order read), and
|
|
398 |
one that should coalesce.
|
|
399 |
"""
|
|
400 |
self.assertOffsetSerialisation([], '', |
|
401 |
self.smart_client, self.smart_server) |
|
402 |
self.assertOffsetSerialisation([(1,2)], '1,2', |
|
403 |
self.smart_client, self.smart_server) |
|
404 |
self.assertOffsetSerialisation([(10,40), (0,5)], '10,40\n0,5', |
|
405 |
self.smart_client, self.smart_server) |
|
406 |
self.assertOffsetSerialisation([(1,2), (3,4), (100, 200)], |
|
407 |
'1,2\n3,4\n100,200', self.smart_client, self.smart_server) |
|
408 |
||
409 |
||
|
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
410 |
# TODO: Client feature that does get_bundle and then installs that into a
|
411 |
# branch; this can be used in place of the regular pull/fetch operation when
|
|
412 |
# coming from a smart server.
|
|
413 |
#
|
|
414 |
# TODO: Eventually, want to do a 'branch' command by fetching the whole
|
|
415 |
# history as one big bundle. How?
|
|
416 |
#
|
|
417 |
# The branch command does 'br_from.sprout', which tries to preserve the same
|
|
418 |
# format. We don't necessarily even want that.
|
|
419 |
#
|
|
420 |
# It might be simpler to handle cmd_pull first, which does a simpler fetch()
|
|
421 |
# operation from one branch into another. It already has some code for
|
|
422 |
# pulling from a bundle, which it does by trying to see if the destination is
|
|
423 |
# a bundle file. So it seems the logic for pull ought to be:
|
|
424 |
#
|
|
425 |
# - if it's a smart server, get a bundle from there and install that
|
|
426 |
# - if it's a bundle, install that
|
|
427 |
# - if it's a branch, pull from there
|
|
428 |
#
|
|
429 |
# Getting a bundle from a smart server is a bit different from reading a
|
|
430 |
# bundle from a URL:
|
|
431 |
#
|
|
432 |
# - we can reasonably remember the URL we last read from
|
|
433 |
# - you can specify a revision number to pull, and we need to pass it across
|
|
434 |
# to the server as a limit on what will be requested
|
|
435 |
#
|
|
436 |
# TODO: Given a URL, determine whether it is a smart server or not (or perhaps
|
|
437 |
# otherwise whether it's a bundle?) Should this be a property or method of
|
|
438 |
# the transport? For the ssh protocol, we always know it's a smart server.
|
|
439 |
# For http, we potentially need to probe. But if we're explicitly given
|
|
440 |
# bzr+http:// then we can skip that for now.
|