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