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