/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1
# Copyright (C) 2006, 2007 Canonical Ltd
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
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 remote bzrdir/branch/repo/etc
18
19
These are proxy objects which act on remote objects by sending messages
20
through a smart client.  The proxies are to be created when attempting to open
21
the object given a transport that supports smartserver rpc operations. 
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
22
23
These tests correspond to tests.test_smart, which exercises the server side.
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
24
"""
25
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
26
from cStringIO import StringIO
27
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
28
from bzrlib import (
29
    bzrdir,
30
    errors,
31
    remote,
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
32
    repository,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
33
    tests,
34
    )
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
35
from bzrlib.branch import Branch
36
from bzrlib.bzrdir import BzrDir, BzrDirFormat
37
from bzrlib.remote import (
38
    RemoteBranch,
39
    RemoteBzrDir,
40
    RemoteBzrDirFormat,
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
41
    RemoteRepository,
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
42
    )
43
from bzrlib.revision import NULL_REVISION
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
44
from bzrlib.smart import server, medium
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
45
from bzrlib.smart.client import _SmartClient
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
46
from bzrlib.transport.memory import MemoryTransport
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
47
from bzrlib.transport.remote import RemoteTransport
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
48
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)
49
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
50
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
51
52
    def setUp(self):
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
53
        self.transport_server = server.SmartTCPServer_for_testing
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
54
        super(BasicRemoteObjectTests, self).setUp()
55
        self.transport = self.get_transport()
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
56
        self.client = self.transport.get_smart_client()
57
        # make a branch that can be opened over the smart transport
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
58
        self.local_wt = BzrDir.create_standalone_workingtree('.')
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
59
2018.5.171 by Andrew Bennetts
Disconnect RemoteTransports in some tests to avoid tripping up test_strace with leftover threads from previous tests.
60
    def tearDown(self):
61
        self.transport.disconnect()
62
        tests.TestCaseWithTransport.tearDown(self)
63
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
64
    def test_create_remote_bzrdir(self):
65
        b = remote.RemoteBzrDir(self.transport)
66
        self.assertIsInstance(b, BzrDir)
67
68
    def test_open_remote_branch(self):
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
69
        # open a standalone branch in the working directory
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
70
        b = remote.RemoteBzrDir(self.transport)
71
        branch = b.open_branch()
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
72
        self.assertIsInstance(branch, Branch)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
73
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
74
    def test_remote_repository(self):
75
        b = BzrDir.open_from_transport(self.transport)
76
        repo = b.open_repository()
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
77
        revid = u'\xc823123123'.encode('utf8')
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
78
        self.assertFalse(repo.has_revision(revid))
79
        self.local_wt.commit(message='test commit', rev_id=revid)
80
        self.assertTrue(repo.has_revision(revid))
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
81
82
    def test_remote_branch_revision_history(self):
83
        b = BzrDir.open_from_transport(self.transport).open_branch()
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
84
        self.assertEqual([], b.revision_history())
85
        r1 = self.local_wt.commit('1st commit')
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
86
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
87
        self.assertEqual([r1, r2], b.revision_history())
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
88
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
89
    def test_find_correct_format(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)
90
        """Should open a RemoteBzrDir over a RemoteTransport"""
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
91
        fmt = BzrDirFormat.find_format(self.transport)
2018.5.169 by Andrew Bennetts
Add a _server_formats flag to BzrDir.open_from_transport and BzrDirFormat.find_format, make RemoteBranch.control_files into a property.
92
        self.assertTrue(RemoteBzrDirFormat
93
                        in BzrDirFormat._control_server_formats)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
94
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
95
96
    def test_open_detected_smart_format(self):
97
        fmt = BzrDirFormat.find_format(self.transport)
98
        d = fmt.open(self.transport)
99
        self.assertIsInstance(d, BzrDir)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
100
2477.1.1 by Martin Pool
Add RemoteBranch repr
101
    def test_remote_branch_repr(self):
102
        b = BzrDir.open_from_transport(self.transport).open_branch()
103
        self.assertStartsWith(str(b), 'RemoteBranch(')
104
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
105
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
106
class FakeProtocol(object):
107
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
108
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
109
    def __init__(self, body, fake_client):
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
110
        self._body_buffer = StringIO(body)
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
111
        self._fake_client = fake_client
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
112
113
    def read_body_bytes(self, count=-1):
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
114
        bytes = self._body_buffer.read(count)
115
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
116
            self._fake_client.expecting_body = False
117
        return bytes
118
119
    def cancel_read_body(self):
120
        self._fake_client.expecting_body = False
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
121
122
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
123
class FakeClient(_SmartClient):
124
    """Lookalike for _SmartClient allowing testing."""
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
125
    
126
    def __init__(self, responses):
127
        # We don't call the super init because there is no medium.
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
128
        """Create a FakeClient.
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
129
130
        :param respones: A list of response-tuple, body-data pairs to be sent
131
            back to callers.
132
        """
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
133
        self.responses = responses
134
        self._calls = []
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
135
        self.expecting_body = False
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
136
137
    def call(self, method, *args):
138
        self._calls.append(('call', method, args))
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
139
        return self.responses.pop(0)[0]
140
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
141
    def call_expecting_body(self, method, *args):
142
        self._calls.append(('call_expecting_body', method, args))
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
143
        result = self.responses.pop(0)
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
144
        self.expecting_body = True
145
        return result[0], FakeProtocol(result[1], self)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
146
147
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
148
class TestBzrDirOpenBranch(tests.TestCase):
149
150
    def test_branch_present(self):
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
151
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no'), )])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
152
        transport = MemoryTransport()
153
        transport.mkdir('quack')
154
        transport = transport.clone('quack')
155
        bzrdir = RemoteBzrDir(transport, _client=client)
156
        result = bzrdir.open_branch()
157
        self.assertEqual(
158
            [('call', 'BzrDir.open_branch', ('///quack/',)),
159
             ('call', 'BzrDir.find_repository', ('///quack/',))],
160
            client._calls)
161
        self.assertIsInstance(result, RemoteBranch)
162
        self.assertEqual(bzrdir, result.bzrdir)
163
164
    def test_branch_missing(self):
165
        client = FakeClient([(('nobranch',), )])
166
        transport = MemoryTransport()
167
        transport.mkdir('quack')
168
        transport = transport.clone('quack')
169
        bzrdir = RemoteBzrDir(transport, _client=client)
170
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
171
        self.assertEqual(
172
            [('call', 'BzrDir.open_branch', ('///quack/',))],
173
            client._calls)
174
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
175
    def check_open_repository(self, rich_root, subtrees):
176
        if rich_root:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
177
            rich_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
178
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
179
            rich_response = 'no'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
180
        if subtrees:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
181
            subtree_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
182
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
183
            subtree_response = 'no'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
184
        client = FakeClient([(('ok', '', rich_response, subtree_response), ),])
185
        transport = MemoryTransport()
186
        transport.mkdir('quack')
187
        transport = transport.clone('quack')
188
        bzrdir = RemoteBzrDir(transport, _client=client)
189
        result = bzrdir.open_repository()
190
        self.assertEqual(
191
            [('call', 'BzrDir.find_repository', ('///quack/',))],
192
            client._calls)
193
        self.assertIsInstance(result, RemoteRepository)
194
        self.assertEqual(bzrdir, result.bzrdir)
195
        self.assertEqual(rich_root, result._format.rich_root_data)
2018.5.138 by Robert Collins
Merge bzr.dev.
196
        self.assertEqual(subtrees, result._format.supports_tree_reference)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
197
198
    def test_open_repository_sets_format_attributes(self):
199
        self.check_open_repository(True, True)
200
        self.check_open_repository(False, True)
201
        self.check_open_repository(True, False)
202
        self.check_open_repository(False, False)
203
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
204
    def test_old_server(self):
205
        """RemoteBzrDirFormat should fail to probe if the server version is too
206
        old.
207
        """
208
        self.assertRaises(errors.NotBranchError,
209
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
210
211
212
class OldSmartClient(object):
213
    """A fake smart client for test_old_version that just returns a version one
214
    response to the 'hello' (query version) command.
215
    """
216
217
    def get_request(self):
218
        input_file = StringIO('ok\x011\n')
219
        output_file = StringIO()
220
        client_medium = medium.SmartSimplePipesClientMedium(
221
            input_file, output_file)
222
        return medium.SmartClientStreamMediumRequest(client_medium)
223
224
225
class OldServerTransport(object):
226
    """A fake transport for test_old_server that reports it's smart server
227
    protocol version as version one.
228
    """
229
230
    def __init__(self):
231
        self.base = 'fake:'
232
233
    def get_smart_client(self):
234
        return OldSmartClient()
235
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
236
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
237
class TestBranchLastRevisionInfo(tests.TestCase):
238
239
    def test_empty_branch(self):
240
        # in an empty branch we decode the response properly
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
241
        client = FakeClient([(('ok', '0', 'null:'), )])
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
242
        transport = MemoryTransport()
243
        transport.mkdir('quack')
244
        transport = transport.clone('quack')
245
        # we do not want bzrdir to make any remote calls
246
        bzrdir = RemoteBzrDir(transport, _client=False)
247
        branch = RemoteBranch(bzrdir, None, _client=client)
248
        result = branch.last_revision_info()
249
250
        self.assertEqual(
251
            [('call', 'Branch.last_revision_info', ('///quack/',))],
252
            client._calls)
253
        self.assertEqual((0, NULL_REVISION), result)
254
255
    def test_non_empty_branch(self):
256
        # in a non-empty branch we also decode the response properly
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
257
        revid = u'\xc8'.encode('utf8')
258
        client = FakeClient([(('ok', '2', revid), )])
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
259
        transport = MemoryTransport()
260
        transport.mkdir('kwaak')
261
        transport = transport.clone('kwaak')
262
        # we do not want bzrdir to make any remote calls
263
        bzrdir = RemoteBzrDir(transport, _client=False)
264
        branch = RemoteBranch(bzrdir, None, _client=client)
265
        result = branch.last_revision_info()
266
267
        self.assertEqual(
268
            [('call', 'Branch.last_revision_info', ('///kwaak/',))],
269
            client._calls)
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
270
        self.assertEqual((2, revid), result)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
271
272
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
273
class TestBranchSetLastRevision(tests.TestCase):
274
275
    def test_set_empty(self):
276
        # set_revision_history([]) is translated to calling
277
        # Branch.set_last_revision(path, '') on the wire.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
278
        client = FakeClient([
279
            # lock_write
280
            (('ok', 'branch token', 'repo token'), ),
281
            # set_last_revision
282
            (('ok',), ),
283
            # unlock
284
            (('ok',), )])
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
285
        transport = MemoryTransport()
286
        transport.mkdir('branch')
287
        transport = transport.clone('branch')
288
289
        bzrdir = RemoteBzrDir(transport, _client=False)
290
        branch = RemoteBranch(bzrdir, None, _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
291
        # This is a hack to work around the problem that RemoteBranch currently
292
        # unnecessarily invokes _ensure_real upon a call to lock_write.
293
        branch._ensure_real = lambda: None
294
        branch.lock_write()
295
        client._calls = []
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
296
        result = branch.set_revision_history([])
297
        self.assertEqual(
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
298
            [('call', 'Branch.set_last_revision',
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
299
                ('///branch/', 'branch token', 'repo token', 'null:'))],
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
300
            client._calls)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
301
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
302
        self.assertEqual(None, result)
303
304
    def test_set_nonempty(self):
305
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
306
        # Branch.set_last_revision(path, rev-idN) on the wire.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
307
        client = FakeClient([
308
            # lock_write
309
            (('ok', 'branch token', 'repo token'), ),
310
            # set_last_revision
311
            (('ok',), ),
312
            # unlock
313
            (('ok',), )])
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
314
        transport = MemoryTransport()
315
        transport.mkdir('branch')
316
        transport = transport.clone('branch')
317
318
        bzrdir = RemoteBzrDir(transport, _client=False)
319
        branch = RemoteBranch(bzrdir, None, _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
320
        # This is a hack to work around the problem that RemoteBranch currently
321
        # unnecessarily invokes _ensure_real upon a call to lock_write.
322
        branch._ensure_real = lambda: None
323
        # Lock the branch, reset the record of remote calls.
324
        branch.lock_write()
325
        client._calls = []
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
326
327
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
328
        self.assertEqual(
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
329
            [('call', 'Branch.set_last_revision',
330
                ('///branch/', 'branch token', 'repo token', 'rev-id2'))],
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
331
            client._calls)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
332
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
333
        self.assertEqual(None, result)
334
335
    def test_no_such_revision(self):
336
        # A response of 'NoSuchRevision' is translated into an exception.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
337
        client = FakeClient([
338
            # lock_write
339
            (('ok', 'branch token', 'repo token'), ),
340
            # set_last_revision
341
            (('NoSuchRevision', 'rev-id'), ),
342
            # unlock
343
            (('ok',), )])
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
344
        transport = MemoryTransport()
345
        transport.mkdir('branch')
346
        transport = transport.clone('branch')
347
348
        bzrdir = RemoteBzrDir(transport, _client=False)
349
        branch = RemoteBranch(bzrdir, None, _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
350
        branch._ensure_real = lambda: None
351
        branch.lock_write()
352
        client._calls = []
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
353
354
        self.assertRaises(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
355
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
356
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
357
358
2018.5.169 by Andrew Bennetts
Add a _server_formats flag to BzrDir.open_from_transport and BzrDirFormat.find_format, make RemoteBranch.control_files into a property.
359
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
360
    """Test branch.control_files api munging...
361
2018.5.169 by Andrew Bennetts
Add a _server_formats flag to BzrDir.open_from_transport and BzrDirFormat.find_format, make RemoteBranch.control_files into a property.
362
    We special case RemoteBranch.control_files.get('branch.conf') to
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
363
    call a specific API so that RemoteBranch's can intercept configuration
364
    file reading, allowing them to signal to the client about things like
365
    'email is configured for commits'.
366
    """
367
368
    def test_get_branch_conf(self):
369
        # in an empty branch we decode the response properly
370
        client = FakeClient([(('ok', ), 'config file body')])
2018.5.169 by Andrew Bennetts
Add a _server_formats flag to BzrDir.open_from_transport and BzrDirFormat.find_format, make RemoteBranch.control_files into a property.
371
        # we need to make a real branch because the remote_branch.control_files
372
        # will trigger _ensure_real.
373
        branch = self.make_branch('quack')
374
        transport = branch.bzrdir.root_transport
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
375
        # we do not want bzrdir to make any remote calls
376
        bzrdir = RemoteBzrDir(transport, _client=False)
377
        branch = RemoteBranch(bzrdir, None, _client=client)
378
        result = branch.control_files.get('branch.conf')
379
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
380
            [('call_expecting_body', 'Branch.get_config_file', ('///quack/',))],
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
381
            client._calls)
382
        self.assertEqual('config file body', result.read())
383
384
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
385
class TestBranchLockWrite(tests.TestCase):
386
387
    def test_lock_write_unlockable(self):
388
        client = FakeClient([(('UnlockableTransport', ), '')])
389
        transport = MemoryTransport()
390
        transport.mkdir('quack')
391
        transport = transport.clone('quack')
392
        # we do not want bzrdir to make any remote calls
393
        bzrdir = RemoteBzrDir(transport, _client=False)
394
        branch = RemoteBranch(bzrdir, None, _client=client)
395
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
396
        self.assertEqual(
397
            [('call', 'Branch.lock_write', ('///quack/', '', ''))],
398
            client._calls)
399
400
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
401
class TestTransportIsReadonly(tests.TestCase):
402
403
    def test_true(self):
404
        client = FakeClient([(('yes',), '')])
405
        transport = RemoteTransport('bzr://example.com/', medium=False,
406
                                    _client=client)
407
        self.assertEqual(True, transport.is_readonly())
408
        self.assertEqual(
409
            [('call', 'Transport.is_readonly', ())],
410
            client._calls)
411
412
    def test_false(self):
413
        client = FakeClient([(('no',), '')])
414
        transport = RemoteTransport('bzr://example.com/', medium=False,
415
                                    _client=client)
416
        self.assertEqual(False, transport.is_readonly())
417
        self.assertEqual(
418
            [('call', 'Transport.is_readonly', ())],
419
            client._calls)
420
421
    def test_error_from_old_server(self):
422
        """bzr 0.15 and earlier servers don't recognise the is_readonly verb.
423
        
424
        Clients should treat it as a "no" response, because is_readonly is only
425
        advisory anyway (a transport could be read-write, but then the
426
        underlying filesystem could be readonly anyway).
427
        """
428
        client = FakeClient([(
429
            ('error', "Generic bzr smart protocol error: "
430
                      "bad request 'Transport.is_readonly'"), '')])
431
        transport = RemoteTransport('bzr://example.com/', medium=False,
432
                                    _client=client)
433
        self.assertEqual(False, transport.is_readonly())
434
        self.assertEqual(
435
            [('call', 'Transport.is_readonly', ())],
436
            client._calls)
437
2471.2.1 by Andrew Bennetts
Fix trivial incompatibility with bzr 0.11 servers, which give a slightly different error to bzr 0.15 servers.
438
    def test_error_from_old_0_11_server(self):
439
        """Same as test_error_from_old_server, but with the slightly different
440
        error message from bzr 0.11 servers.
441
        """
442
        client = FakeClient([(
443
            ('error', "Generic bzr smart protocol error: "
444
                      "bad request u'Transport.is_readonly'"), '')])
445
        transport = RemoteTransport('bzr://example.com/', medium=False,
446
                                    _client=client)
447
        self.assertEqual(False, transport.is_readonly())
448
        self.assertEqual(
449
            [('call', 'Transport.is_readonly', ())],
450
            client._calls)
451
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
452
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
453
class TestRemoteRepository(tests.TestCase):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
454
    """Base for testing RemoteRepository protocol usage.
455
    
456
    These tests contain frozen requests and responses.  We want any changes to 
457
    what is sent or expected to be require a thoughtful update to these tests
458
    because they might break compatibility with different-versioned servers.
459
    """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
460
461
    def setup_fake_client_and_repository(self, responses, transport_path):
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
462
        """Create the fake client and repository for testing with.
463
        
464
        There's no real server here; we just have canned responses sent
465
        back one by one.
466
        
467
        :param transport_path: Path below the root of the MemoryTransport
468
            where the repository will be created.
469
        """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
470
        client = FakeClient(responses)
471
        transport = MemoryTransport()
472
        transport.mkdir(transport_path)
473
        transport = transport.clone(transport_path)
474
        # we do not want bzrdir to make any remote calls
475
        bzrdir = RemoteBzrDir(transport, _client=False)
476
        repo = RemoteRepository(bzrdir, None, _client=client)
477
        return repo, client
478
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
479
2018.12.2 by Andrew Bennetts
Remove some duplicate code in test_remote
480
class TestRepositoryGatherStats(TestRemoteRepository):
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
481
482
    def test_revid_none(self):
483
        # ('ok',), body with revisions and size
484
        responses = [(('ok', ), 'revisions: 2\nsize: 18\n')]
485
        transport_path = 'quack'
486
        repo, client = self.setup_fake_client_and_repository(
487
            responses, transport_path)
488
        result = repo.gather_stats(None)
489
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
490
            [('call_expecting_body', 'Repository.gather_stats',
491
             ('///quack/','','no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
492
            client._calls)
493
        self.assertEqual({'revisions': 2, 'size': 18}, result)
494
495
    def test_revid_no_committers(self):
496
        # ('ok',), body without committers
497
        responses = [(('ok', ),
498
                      'firstrev: 123456.300 3600\n'
499
                      'latestrev: 654231.400 0\n'
500
                      'revisions: 2\n'
501
                      'size: 18\n')]
502
        transport_path = 'quick'
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
503
        revid = u'\xc8'.encode('utf8')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
504
        repo, client = self.setup_fake_client_and_repository(
505
            responses, transport_path)
506
        result = repo.gather_stats(revid)
507
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
508
            [('call_expecting_body', 'Repository.gather_stats',
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
509
              ('///quick/', revid, 'no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
510
            client._calls)
511
        self.assertEqual({'revisions': 2, 'size': 18,
512
                          'firstrev': (123456.300, 3600),
513
                          'latestrev': (654231.400, 0),},
514
                         result)
515
516
    def test_revid_with_committers(self):
517
        # ('ok',), body with committers
518
        responses = [(('ok', ),
519
                      'committers: 128\n'
520
                      'firstrev: 123456.300 3600\n'
521
                      'latestrev: 654231.400 0\n'
522
                      'revisions: 2\n'
523
                      'size: 18\n')]
524
        transport_path = 'buick'
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
525
        revid = u'\xc8'.encode('utf8')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
526
        repo, client = self.setup_fake_client_and_repository(
527
            responses, transport_path)
528
        result = repo.gather_stats(revid, True)
529
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
530
            [('call_expecting_body', 'Repository.gather_stats',
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
531
              ('///buick/', revid, 'yes'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
532
            client._calls)
533
        self.assertEqual({'revisions': 2, 'size': 18,
534
                          'committers': 128,
535
                          'firstrev': (123456.300, 3600),
536
                          'latestrev': (654231.400, 0),},
537
                         result)
538
539
2018.5.68 by Wouter van Heyst
Merge RemoteRepository.gather_stats.
540
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
541
    
542
    def test_null_revision(self):
543
        # a null revision has the predictable result {}, we should have no wire
544
        # traffic when calling it with this argument
545
        responses = [(('notused', ), '')]
546
        transport_path = 'empty'
547
        repo, client = self.setup_fake_client_and_repository(
548
            responses, transport_path)
549
        result = repo.get_revision_graph(NULL_REVISION)
550
        self.assertEqual([], client._calls)
551
        self.assertEqual({}, result)
552
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
553
    def test_none_revision(self):
554
        # with none we want the entire graph
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
555
        r1 = u'\u0e33'.encode('utf8')
556
        r2 = u'\u0dab'.encode('utf8')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
557
        lines = [' '.join([r2, r1]), r1]
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
558
        encoded_body = '\n'.join(lines)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
559
560
        responses = [(('ok', ), encoded_body)]
561
        transport_path = 'sinhala'
562
        repo, client = self.setup_fake_client_and_repository(
563
            responses, transport_path)
564
        result = repo.get_revision_graph()
565
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
566
            [('call_expecting_body', 'Repository.get_revision_graph',
567
             ('///sinhala/', ''))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
568
            client._calls)
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
569
        self.assertEqual({r1: (), r2: (r1, )}, result)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
570
571
    def test_specific_revision(self):
572
        # with a specific revision we want the graph for that
573
        # with none we want the entire graph
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
574
        r11 = u'\u0e33'.encode('utf8')
575
        r12 = u'\xc9'.encode('utf8')
576
        r2 = u'\u0dab'.encode('utf8')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
577
        lines = [' '.join([r2, r11, r12]), r11, r12]
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
578
        encoded_body = '\n'.join(lines)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
579
580
        responses = [(('ok', ), encoded_body)]
581
        transport_path = 'sinhala'
582
        repo, client = self.setup_fake_client_and_repository(
583
            responses, transport_path)
584
        result = repo.get_revision_graph(r2)
585
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
586
            [('call_expecting_body', 'Repository.get_revision_graph',
587
             ('///sinhala/', r2))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
588
            client._calls)
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
589
        self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
590
591
    def test_no_such_revision(self):
592
        revid = '123'
593
        responses = [(('nosuchrevision', revid), '')]
594
        transport_path = 'sinhala'
595
        repo, client = self.setup_fake_client_and_repository(
596
            responses, transport_path)
597
        # also check that the right revision is reported in the error
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
598
        self.assertRaises(errors.NoSuchRevision,
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
599
            repo.get_revision_graph, revid)
600
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
601
            [('call_expecting_body', 'Repository.get_revision_graph',
602
             ('///sinhala/', revid))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
603
            client._calls)
604
605
        
606
class TestRepositoryIsShared(TestRemoteRepository):
607
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
608
    def test_is_shared(self):
609
        # ('yes', ) for Repository.is_shared -> 'True'.
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
610
        responses = [(('yes', ), )]
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
611
        transport_path = 'quack'
612
        repo, client = self.setup_fake_client_and_repository(
613
            responses, transport_path)
614
        result = repo.is_shared()
615
        self.assertEqual(
616
            [('call', 'Repository.is_shared', ('///quack/',))],
617
            client._calls)
618
        self.assertEqual(True, result)
619
620
    def test_is_not_shared(self):
621
        # ('no', ) for Repository.is_shared -> 'False'.
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
622
        responses = [(('no', ), )]
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
623
        transport_path = 'qwack'
624
        repo, client = self.setup_fake_client_and_repository(
625
            responses, transport_path)
626
        result = repo.is_shared()
627
        self.assertEqual(
628
            [('call', 'Repository.is_shared', ('///qwack/',))],
629
            client._calls)
630
        self.assertEqual(False, result)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
631
632
633
class TestRepositoryLockWrite(TestRemoteRepository):
634
635
    def test_lock_write(self):
636
        responses = [(('ok', 'a token'), '')]
637
        transport_path = 'quack'
638
        repo, client = self.setup_fake_client_and_repository(
639
            responses, transport_path)
640
        result = repo.lock_write()
641
        self.assertEqual(
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
642
            [('call', 'Repository.lock_write', ('///quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
643
            client._calls)
644
        self.assertEqual('a token', result)
645
646
    def test_lock_write_already_locked(self):
647
        responses = [(('LockContention', ), '')]
648
        transport_path = 'quack'
649
        repo, client = self.setup_fake_client_and_repository(
650
            responses, transport_path)
651
        self.assertRaises(errors.LockContention, repo.lock_write)
652
        self.assertEqual(
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
653
            [('call', 'Repository.lock_write', ('///quack/', ''))],
654
            client._calls)
655
656
    def test_lock_write_unlockable(self):
657
        responses = [(('UnlockableTransport', ), '')]
658
        transport_path = 'quack'
659
        repo, client = self.setup_fake_client_and_repository(
660
            responses, transport_path)
661
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
662
        self.assertEqual(
663
            [('call', 'Repository.lock_write', ('///quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
664
            client._calls)
665
666
667
class TestRepositoryUnlock(TestRemoteRepository):
668
669
    def test_unlock(self):
670
        responses = [(('ok', 'a token'), ''),
671
                     (('ok',), '')]
672
        transport_path = 'quack'
673
        repo, client = self.setup_fake_client_and_repository(
674
            responses, transport_path)
675
        repo.lock_write()
676
        repo.unlock()
677
        self.assertEqual(
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
678
            [('call', 'Repository.lock_write', ('///quack/', '')),
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
679
             ('call', 'Repository.unlock', ('///quack/', 'a token'))],
680
            client._calls)
681
682
    def test_unlock_wrong_token(self):
683
        # If somehow the token is wrong, unlock will raise TokenMismatch.
684
        responses = [(('ok', 'a token'), ''),
685
                     (('TokenMismatch',), '')]
686
        transport_path = 'quack'
687
        repo, client = self.setup_fake_client_and_repository(
688
            responses, transport_path)
689
        repo.lock_write()
690
        self.assertRaises(errors.TokenMismatch, repo.unlock)
691
692
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
693
class TestRepositoryHasRevision(TestRemoteRepository):
694
695
    def test_none(self):
696
        # repo.has_revision(None) should not cause any traffic.
697
        transport_path = 'quack'
698
        responses = None
699
        repo, client = self.setup_fake_client_and_repository(
700
            responses, transport_path)
701
702
        # The null revision is always there, so has_revision(None) == True.
703
        self.assertEqual(True, repo.has_revision(None))
704
705
        # The remote repo shouldn't be accessed.
706
        self.assertEqual([], client._calls)
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
707
708
709
class TestRepositoryTarball(TestRemoteRepository):
710
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
711
    # This is a canned tarball reponse we can validate against
2018.18.18 by Martin Pool
reformat
712
    tarball_content = (
2018.18.23 by Martin Pool
review cleanups
713
        'QlpoOTFBWSZTWdGkj3wAAWF/k8aQACBIB//A9+8cIX/v33AACEAYABAECEACNz'
714
        'JqsgJJFPTSnk1A3qh6mTQAAAANPUHkagkSTEkaA09QaNAAAGgAAAcwCYCZGAEY'
715
        'mJhMJghpiaYBUkKammSHqNMZQ0NABkNAeo0AGneAevnlwQoGzEzNVzaYxp/1Uk'
716
        'xXzA1CQX0BJMZZLcPBrluJir5SQyijWHYZ6ZUtVqqlYDdB2QoCwa9GyWwGYDMA'
717
        'OQYhkpLt/OKFnnlT8E0PmO8+ZNSo2WWqeCzGB5fBXZ3IvV7uNJVE7DYnWj6qwB'
718
        'k5DJDIrQ5OQHHIjkS9KqwG3mc3t+F1+iujb89ufyBNIKCgeZBWrl5cXxbMGoMs'
719
        'c9JuUkg5YsiVcaZJurc6KLi6yKOkgCUOlIlOpOoXyrTJjK8ZgbklReDdwGmFgt'
720
        'dkVsAIslSVCd4AtACSLbyhLHryfb14PKegrVDba+U8OL6KQtzdM5HLjAc8/p6n'
721
        '0lgaWU8skgO7xupPTkyuwheSckejFLK5T4ZOo0Gda9viaIhpD1Qn7JqqlKAJqC'
722
        'QplPKp2nqBWAfwBGaOwVrz3y1T+UZZNismXHsb2Jq18T+VaD9k4P8DqE3g70qV'
723
        'JLurpnDI6VS5oqDDPVbtVjMxMxMg4rzQVipn2Bv1fVNK0iq3Gl0hhnnHKm/egy'
724
        'nWQ7QH/F3JFOFCQ0aSPfA='
725
        ).decode('base64')
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
726
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
727
    def test_repository_tarball(self):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
728
        # Test that Repository.tarball generates the right operations
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
729
        transport_path = 'repo'
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
730
        expected_responses = [(('ok',), self.tarball_content),
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
731
            ]
2018.18.14 by Martin Pool
merge hpss again; restore incorrectly removed RemoteRepository.break_lock
732
        expected_calls = [('call_expecting_body', 'Repository.tarball',
733
                           ('///repo/', 'bz2',),),
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
734
            ]
735
        remote_repo, client = self.setup_fake_client_and_repository(
736
            expected_responses, transport_path)
737
        # Now actually ask for the tarball
2018.18.25 by Martin Pool
Repository.tarball fixes for python2.4
738
        tarball_file = remote_repo._get_tarball('bz2')
739
        try:
740
            self.assertEqual(expected_calls, client._calls)
741
            self.assertEqual(self.tarball_content, tarball_file.read())
742
        finally:
743
            tarball_file.close()
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
744
2018.18.24 by Martin Pool
Merge Repository.sprout refactoring, and make that use Repository.tarball
745
    def test_sprout_uses_tarball(self):
746
        # RemoteRepository.sprout should try to use the
2018.18.17 by Martin Pool
Update and reenable rpc-level tests for Repository.tarball
747
        # tarball command rather than accessing all the files
748
        transport_path = 'srcrepo'
749
        expected_responses = [(('ok',), self.tarball_content),
750
            ]
751
        expected_calls = [('call2', 'Repository.tarball', ('///srcrepo/', 'bz2',),),
752
            ]
753
        remote_repo, client = self.setup_fake_client_and_repository(
754
            expected_responses, transport_path)
755
        # make a regular local repository to receive the results
756
        dest_transport = MemoryTransport()
757
        dest_transport.mkdir('destrepo')
758
        bzrdir_format = bzrdir.format_registry.make_bzrdir('default')
759
        dest_bzrdir = bzrdir_format.initialize_on_transport(dest_transport)
760
        # try to copy...
2018.18.24 by Martin Pool
Merge Repository.sprout refactoring, and make that use Repository.tarball
761
        remote_repo.sprout(dest_bzrdir)
2018.18.17 by Martin Pool
Update and reenable rpc-level tests for Repository.tarball
762
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
763
    def test_backwards_compatibility(self):
2814.10.3 by Andrew Bennetts
Improve the test.
764
        """If the server doesn't recognise this request, fallback to VFS.
765
        
766
        This happens when a current client talks to an older server that
767
        doesn't implement 'Repository.tarball'.
768
        """
769
        # Make a regular local repository to receive the results
770
        dest_transport = MemoryTransport()
771
        dest_transport.mkdir('destrepo')
772
        bzrdir_format = bzrdir.format_registry.make_bzrdir('default')
773
        dest_bzrdir = bzrdir_format.initialize_on_transport(dest_transport)
774
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
775
        error_msg = (
776
            "Generic bzr smart protocol error: "
777
            "bad request 'Repository.tarball'")
778
        responses = [(('error', error_msg), '')]
779
        remote_repo, client = self.setup_fake_client_and_repository(
780
            responses, 'path')
2814.10.3 by Andrew Bennetts
Improve the test.
781
        mock_real_repo = MockRealRepository()
782
        remote_repo._real_repository = mock_real_repo
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
783
784
        # try to copy...
785
        remote_repo.sprout(dest_bzrdir)
786
2814.10.3 by Andrew Bennetts
Improve the test.
787
        self.assertEqual([('sprout', dest_bzrdir, None)], mock_real_repo.calls,
788
            "RemoteRepository didn't fallback to the real repository correctly")
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
789
        self.failIf(client.expecting_body,
790
            "The protocol has been left in an unclean state that will cause "
791
            "TooManyConcurrentRequests errors.")
792
793
794
class MockRealRepository(object):
795
    """Mock of a RemoteRepository's '_real_repository' attribute.
796
    
797
    Used by TestRepositoryTarball.test_backwards_compatibility.
798
    """
799
2814.10.3 by Andrew Bennetts
Improve the test.
800
    def __init__(self):
801
        self.calls = []
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
802
803
    def sprout(self, to_bzrdir, revision_id=None):
2814.10.3 by Andrew Bennetts
Improve the test.
804
        self.calls.append(('sprout', to_bzrdir, revision_id))
2814.10.1 by Andrew Bennetts
Cope gracefully if the server doesn't support the Repository.tarball smart request.
805
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
806
807
class TestRemoteRepositoryCopyContent(tests.TestCaseWithTransport):
808
    """RemoteRepository.copy_content_into optimizations"""
809
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
810
    def test_copy_content_remote_to_local(self):
811
        self.transport_server = server.SmartTCPServer_for_testing
812
        src_repo = self.make_repository('repo1')
813
        src_repo = repository.Repository.open(self.get_url('repo1'))
814
        # At the moment the tarball-based copy_content_into can't write back
815
        # into a smart server.  It would be good if it could upload the
816
        # tarball; once that works we'd have to create repositories of
817
        # different formats. -- mbp 20070410
818
        dest_url = self.get_vfs_only_url('repo2')
819
        dest_bzrdir = BzrDir.create(dest_url)
820
        dest_repo = dest_bzrdir.create_repository()
821
        self.assertFalse(isinstance(dest_repo, RemoteRepository))
822
        self.assertTrue(isinstance(src_repo, RemoteRepository))
823
        src_repo.copy_content_into(dest_repo)