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