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