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