/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3407.2.2 by Martin Pool
Remove special case in RemoteBranchLockableFiles for branch.conf
1
# Copyright (C) 2006, 2007, 2008 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
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
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
3211.5.2 by Robert Collins
Change RemoteRepository.get_parent_map to use bz2 not gzip for compression.
26
import bz2
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
27
from cStringIO import StringIO
28
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
29
from bzrlib import (
3834.3.2 by Andrew Bennetts
Preserve BzrBranch5's _synchronize_history code without affecting Branch or BzrBranch7; add effort test for RemoteBranch.copy_content_into.
30
    bzrdir,
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
31
    config,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
32
    errors,
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
33
    graph,
2535.3.39 by Andrew Bennetts
Tidy some XXXs.
34
    pack,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
35
    remote,
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
36
    repository,
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
37
    smart,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
38
    tests,
3691.2.4 by Martin Pool
Add FakeRemoteTransport to clarify test_remote
39
    urlutils,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
40
    )
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
41
from bzrlib.branch import Branch
42
from bzrlib.bzrdir import BzrDir, BzrDirFormat
43
from bzrlib.remote import (
44
    RemoteBranch,
45
    RemoteBzrDir,
46
    RemoteBzrDirFormat,
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
47
    RemoteRepository,
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
48
    )
49
from bzrlib.revision import NULL_REVISION
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
50
from bzrlib.smart import server, medium
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
51
from bzrlib.smart.client import _SmartClient
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
52
from bzrlib.symbol_versioning import one_four
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
53
from bzrlib.transport import get_transport, http
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
54
from bzrlib.transport.memory import MemoryTransport
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
55
from bzrlib.transport.remote import (
56
    RemoteTransport,
57
    RemoteSSHTransport,
58
    RemoteTCPTransport,
59
)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
60
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)
61
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
62
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
63
64
    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.
65
        self.transport_server = server.SmartTCPServer_for_testing
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
66
        super(BasicRemoteObjectTests, self).setUp()
67
        self.transport = self.get_transport()
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
68
        # 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
69
        self.local_wt = BzrDir.create_standalone_workingtree('.')
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
70
2018.5.171 by Andrew Bennetts
Disconnect RemoteTransports in some tests to avoid tripping up test_strace with leftover threads from previous tests.
71
    def tearDown(self):
72
        self.transport.disconnect()
73
        tests.TestCaseWithTransport.tearDown(self)
74
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
75
    def test_create_remote_bzrdir(self):
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
76
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
77
        self.assertIsInstance(b, BzrDir)
78
79
    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.
80
        # open a standalone branch in the working directory
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
81
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
82
        branch = b.open_branch()
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
83
        self.assertIsInstance(branch, Branch)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
84
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
85
    def test_remote_repository(self):
86
        b = BzrDir.open_from_transport(self.transport)
87
        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.
88
        revid = u'\xc823123123'.encode('utf8')
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
89
        self.assertFalse(repo.has_revision(revid))
90
        self.local_wt.commit(message='test commit', rev_id=revid)
91
        self.assertTrue(repo.has_revision(revid))
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
92
93
    def test_remote_branch_revision_history(self):
94
        b = BzrDir.open_from_transport(self.transport).open_branch()
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
95
        self.assertEqual([], b.revision_history())
96
        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.
97
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
98
        self.assertEqual([r1, r2], b.revision_history())
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
99
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
100
    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)
101
        """Should open a RemoteBzrDir over a RemoteTransport"""
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
102
        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.
103
        self.assertTrue(RemoteBzrDirFormat
104
                        in BzrDirFormat._control_server_formats)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
105
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
106
107
    def test_open_detected_smart_format(self):
108
        fmt = BzrDirFormat.find_format(self.transport)
109
        d = fmt.open(self.transport)
110
        self.assertIsInstance(d, BzrDir)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
111
2477.1.1 by Martin Pool
Add RemoteBranch repr
112
    def test_remote_branch_repr(self):
113
        b = BzrDir.open_from_transport(self.transport).open_branch()
114
        self.assertStartsWith(str(b), 'RemoteBranch(')
115
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
116
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
117
class FakeProtocol(object):
118
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
119
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
120
    def __init__(self, body, fake_client):
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
121
        self.body = body
122
        self._body_buffer = None
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
123
        self._fake_client = fake_client
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
124
125
    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.
126
        if self._body_buffer is None:
127
            self._body_buffer = StringIO(self.body)
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
128
        bytes = self._body_buffer.read(count)
129
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
130
            self._fake_client.expecting_body = False
131
        return bytes
132
133
    def cancel_read_body(self):
134
        self._fake_client.expecting_body = False
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
135
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
136
    def read_streamed_body(self):
137
        return self.body
138
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
139
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
140
class FakeClient(_SmartClient):
141
    """Lookalike for _SmartClient allowing testing."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
142
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
143
    def __init__(self, fake_medium_base='fake base'):
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
144
        """Create a FakeClient."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
145
        self.responses = []
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
146
        self._calls = []
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
147
        self.expecting_body = False
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
148
        # if non-None, this is the list of expected calls, with only the
149
        # method name and arguments included.  the body might be hard to
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
150
        # compute so is not included. If a call is None, that call can
151
        # be anything.
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
152
        self._expected_calls = None
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
153
        _SmartClient.__init__(self, FakeMedium(self._calls, fake_medium_base))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
154
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
155
    def add_expected_call(self, call_name, call_args, response_type,
156
        response_args, response_body=None):
157
        if self._expected_calls is None:
158
            self._expected_calls = []
159
        self._expected_calls.append((call_name, call_args))
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
160
        self.responses.append((response_type, response_args, response_body))
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
161
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
162
    def add_success_response(self, *args):
163
        self.responses.append(('success', args, None))
164
165
    def add_success_response_with_body(self, body, *args):
166
        self.responses.append(('success', args, body))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
167
        if self._expected_calls is not None:
168
            self._expected_calls.append(None)
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
169
170
    def add_error_response(self, *args):
171
        self.responses.append(('error', args))
172
173
    def add_unknown_method_response(self, verb):
174
        self.responses.append(('unknown', verb))
175
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
176
    def finished_test(self):
177
        if self._expected_calls:
178
            raise AssertionError("%r finished but was still expecting %r"
179
                % (self, self._expected_calls[0]))
180
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
181
    def _get_next_response(self):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
182
        try:
183
            response_tuple = self.responses.pop(0)
184
        except IndexError, e:
185
            raise AssertionError("%r didn't expect any more calls"
186
                % (self,))
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
187
        if response_tuple[0] == 'unknown':
188
            raise errors.UnknownSmartMethod(response_tuple[1])
189
        elif response_tuple[0] == 'error':
190
            raise errors.ErrorFromSmartServer(response_tuple[1])
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
191
        return response_tuple
192
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
193
    def _check_call(self, method, args):
194
        if self._expected_calls is None:
195
            # the test should be updated to say what it expects
196
            return
197
        try:
198
            next_call = self._expected_calls.pop(0)
199
        except IndexError:
200
            raise AssertionError("%r didn't expect any more calls "
201
                "but got %r%r"
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
202
                % (self, method, args,))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
203
        if next_call is None:
204
            return
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
205
        if method != next_call[0] or args != next_call[1]:
206
            raise AssertionError("%r expected %r%r "
207
                "but got %r%r"
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
208
                % (self, next_call[0], next_call[1], method, args,))
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
209
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
210
    def call(self, method, *args):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
211
        self._check_call(method, args)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
212
        self._calls.append(('call', method, args))
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
213
        return self._get_next_response()[1]
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
214
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
215
    def call_expecting_body(self, method, *args):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
216
        self._check_call(method, args)
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
217
        self._calls.append(('call_expecting_body', method, args))
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
218
        result = self._get_next_response()
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
219
        self.expecting_body = True
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
220
        return result[1], FakeProtocol(result[2], self)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
221
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.
222
    def call_with_body_bytes_expecting_body(self, method, args, body):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
223
        self._check_call(method, args)
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.
224
        self._calls.append(('call_with_body_bytes_expecting_body', method,
225
            args, body))
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
226
        result = self._get_next_response()
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.
227
        self.expecting_body = True
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
228
        return result[1], FakeProtocol(result[2], self)
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.
229
3842.3.9 by Andrew Bennetts
Backing up the stream so that we can fallback correctly.
230
    def call_with_body_stream(self, args, stream):
231
        # Explicitly consume the stream before checking for an error, because
232
        # that's what happens a real medium.
233
        stream = list(stream)
234
        self._check_call(args[0], args[1:])
235
        self._calls.append(('call_with_body_stream', args[0], args[1:], stream))
236
        return self._get_next_response()[1]
237
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
238
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
239
class FakeMedium(medium.SmartClientMedium):
3104.4.2 by Andrew Bennetts
All tests passing.
240
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
241
    def __init__(self, client_calls, base):
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
242
        medium.SmartClientMedium.__init__(self, base)
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
243
        self._client_calls = client_calls
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.
244
245
    def disconnect(self):
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
246
        self._client_calls.append(('disconnect medium',))
3104.4.2 by Andrew Bennetts
All tests passing.
247
248
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.
249
class TestVfsHas(tests.TestCase):
250
251
    def test_unicode_path(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
252
        client = FakeClient('/')
253
        client.add_success_response('yes',)
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.
254
        transport = RemoteTransport('bzr://localhost/', _client=client)
255
        filename = u'/hell\u00d8'.encode('utf8')
256
        result = transport.has(filename)
257
        self.assertEqual(
258
            [('call', 'has', (filename,))],
259
            client._calls)
260
        self.assertTrue(result)
261
262
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
263
class TestRemote(tests.TestCaseWithMemoryTransport):
4032.1.1 by John Arbash Meinel
Merge the removal of all trailing whitespace, and resolve conflicts.
264
4053.1.2 by Robert Collins
Actually make this branch work.
265
    def get_repo_format(self):
266
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
267
        return reference_bzrdir_format.repository_format
268
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
269
    def disable_verb(self, verb):
270
        """Disable a verb for one test."""
271
        request_handlers = smart.request.request_handlers
272
        orig_method = request_handlers.get(verb)
273
        request_handlers.remove(verb)
274
        def restoreVerb():
275
            request_handlers.register(verb, orig_method)
276
        self.addCleanup(restoreVerb)
277
278
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
279
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
280
    """Tests for the behaviour of client_medium.remote_path_from_transport."""
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
281
282
    def assertRemotePath(self, expected, client_base, transport_base):
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
283
        """Assert that the result of
284
        SmartClientMedium.remote_path_from_transport is the expected value for
285
        a given client_base and transport_base.
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
286
        """
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
287
        client_medium = medium.SmartClientMedium(client_base)
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
288
        transport = get_transport(transport_base)
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
289
        result = client_medium.remote_path_from_transport(transport)
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
290
        self.assertEqual(expected, result)
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
291
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
292
    def test_remote_path_from_transport(self):
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
293
        """SmartClientMedium.remote_path_from_transport calculates a URL for
294
        the given transport relative to the root of the client base URL.
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
295
        """
296
        self.assertRemotePath('xyz/', 'bzr://host/path', 'bzr://host/xyz')
297
        self.assertRemotePath(
298
            'path/xyz/', 'bzr://host/path', 'bzr://host/path/xyz')
299
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
300
    def assertRemotePathHTTP(self, expected, transport_base, relpath):
301
        """Assert that the result of
302
        HttpTransportBase.remote_path_from_transport is the expected value for
303
        a given transport_base and relpath of that transport.  (Note that
304
        HttpTransportBase is a subclass of SmartClientMedium)
305
        """
306
        base_transport = get_transport(transport_base)
307
        client_medium = base_transport.get_smart_medium()
308
        cloned_transport = base_transport.clone(relpath)
309
        result = client_medium.remote_path_from_transport(cloned_transport)
310
        self.assertEqual(expected, result)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
311
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
312
    def test_remote_path_from_transport_http(self):
313
        """Remote paths for HTTP transports are calculated differently to other
314
        transports.  They are just relative to the client base, not the root
315
        directory of the host.
316
        """
317
        for scheme in ['http:', 'https:', 'bzr+http:', 'bzr+https:']:
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
318
            self.assertRemotePathHTTP(
319
                '../xyz/', scheme + '//host/path', '../xyz/')
320
            self.assertRemotePathHTTP(
321
                'xyz/', scheme + '//host/path', 'xyz/')
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
322
323
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
324
class Test_ClientMedium_remote_is_at_least(tests.TestCase):
325
    """Tests for the behaviour of client_medium.remote_is_at_least."""
326
327
    def test_initially_unlimited(self):
328
        """A fresh medium assumes that the remote side supports all
329
        versions.
330
        """
331
        client_medium = medium.SmartClientMedium('dummy base')
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
332
        self.assertFalse(client_medium._is_remote_before((99, 99)))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
333
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
334
    def test__remember_remote_is_before(self):
335
        """Calling _remember_remote_is_before ratchets down the known remote
336
        version.
337
        """
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
338
        client_medium = medium.SmartClientMedium('dummy base')
339
        # Mark the remote side as being less than 1.6.  The remote side may
340
        # still be 1.5.
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
341
        client_medium._remember_remote_is_before((1, 6))
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
342
        self.assertTrue(client_medium._is_remote_before((1, 6)))
343
        self.assertFalse(client_medium._is_remote_before((1, 5)))
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
344
        # Calling _remember_remote_is_before again with a lower value works.
345
        client_medium._remember_remote_is_before((1, 5))
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
346
        self.assertTrue(client_medium._is_remote_before((1, 5)))
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
347
        # You cannot call _remember_remote_is_before with a larger value.
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
348
        self.assertRaises(
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
349
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
350
351
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
352
class TestBzrDirCloningMetaDir(TestRemote):
353
354
    def test_backwards_compat(self):
355
        self.setup_smart_server_with_call_log()
356
        a_dir = self.make_bzrdir('.')
357
        self.reset_smart_call_log()
358
        verb = 'BzrDir.cloning_metadir'
359
        self.disable_verb(verb)
360
        format = a_dir.cloning_metadir()
361
        call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
362
            call.call.method == verb])
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
363
        self.assertEqual(1, call_count)
364
365
    def test_current_server(self):
366
        transport = self.get_transport('.')
367
        transport = transport.clone('quack')
368
        self.make_bzrdir('quack')
369
        client = FakeClient(transport.base)
370
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
371
        control_name = reference_bzrdir_format.network_name()
372
        client.add_expected_call(
373
            'BzrDir.cloning_metadir', ('quack/', 'False'),
374
            'success', (control_name, '', '')),
375
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
376
            _client=client)
377
        result = a_bzrdir.cloning_metadir()
378
        # We should have got a reference control dir with default branch and
379
        # repository formats.
380
        # This pokes a little, just to be sure.
381
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
4070.2.8 by Robert Collins
Really test the current BzrDir.cloning_metadir contract.
382
        self.assertEqual(None, result._repository_format)
383
        self.assertEqual(None, result._branch_format)
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
384
        client.finished_test()
385
386
4053.1.2 by Robert Collins
Actually make this branch work.
387
class TestBzrDirOpenBranch(TestRemote):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
388
389
    def test_branch_present(self):
4053.1.2 by Robert Collins
Actually make this branch work.
390
        reference_format = self.get_repo_format()
391
        network_name = reference_format.network_name()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
392
        transport = MemoryTransport()
393
        transport.mkdir('quack')
394
        transport = transport.clone('quack')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
395
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
396
        client.add_expected_call(
397
            'BzrDir.open_branch', ('quack/',),
398
            'success', ('ok', ''))
399
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
400
            'BzrDir.find_repositoryV3', ('quack/',),
401
            'success', ('ok', '', 'no', 'no', 'no', network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
402
        client.add_expected_call(
403
            'Branch.get_stacked_on_url', ('quack/',),
404
            'error', ('NotStacked',))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
405
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
406
            _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
407
        result = bzrdir.open_branch()
408
        self.assertIsInstance(result, RemoteBranch)
409
        self.assertEqual(bzrdir, result.bzrdir)
3691.2.10 by Martin Pool
Update more test_remote tests
410
        client.finished_test()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
411
412
    def test_branch_missing(self):
413
        transport = MemoryTransport()
414
        transport.mkdir('quack')
415
        transport = transport.clone('quack')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
416
        client = FakeClient(transport.base)
417
        client.add_error_response('nobranch')
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
418
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
419
            _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
420
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
421
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
422
            [('call', 'BzrDir.open_branch', ('quack/',))],
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
423
            client._calls)
424
3211.4.1 by Robert Collins
* ``RemoteBzrDir._get_tree_branch`` no longer triggers ``_ensure_real``,
425
    def test__get_tree_branch(self):
426
        # _get_tree_branch is a form of open_branch, but it should only ask for
427
        # branch opening, not any other network requests.
428
        calls = []
429
        def open_branch():
430
            calls.append("Called")
431
            return "a-branch"
432
        transport = MemoryTransport()
433
        # no requests on the network - catches other api calls being made.
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
434
        client = FakeClient(transport.base)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
435
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
436
            _client=client)
3211.4.1 by Robert Collins
* ``RemoteBzrDir._get_tree_branch`` no longer triggers ``_ensure_real``,
437
        # patch the open_branch call to record that it was called.
438
        bzrdir.open_branch = open_branch
439
        self.assertEqual((None, "a-branch"), bzrdir._get_tree_branch())
440
        self.assertEqual(["Called"], calls)
441
        self.assertEqual([], client._calls)
442
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.
443
    def test_url_quoting_of_path(self):
444
        # Relpaths on the wire should not be URL-escaped.  So "~" should be
445
        # transmitted as "~", not "%7E".
3431.3.1 by Andrew Bennetts
First rough cut of a fix for bug #230550, by adding .base to SmartClientMedia rather than relying on other objects to track this accurately while reusing client media.
446
        transport = RemoteTCPTransport('bzr://localhost/~hello/')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
447
        client = FakeClient(transport.base)
4053.1.2 by Robert Collins
Actually make this branch work.
448
        reference_format = self.get_repo_format()
449
        network_name = reference_format.network_name()
3691.2.10 by Martin Pool
Update more test_remote tests
450
        client.add_expected_call(
451
            'BzrDir.open_branch', ('~hello/',),
452
            'success', ('ok', ''))
453
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
454
            'BzrDir.find_repositoryV3', ('~hello/',),
455
            'success', ('ok', '', 'no', 'no', 'no', network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
456
        client.add_expected_call(
457
            'Branch.get_stacked_on_url', ('~hello/',),
458
            'error', ('NotStacked',))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
459
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
460
            _client=client)
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.
461
        result = bzrdir.open_branch()
3691.2.10 by Martin Pool
Update more test_remote tests
462
        client.finished_test()
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.
463
3221.3.3 by Robert Collins
* Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
464
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
4053.1.2 by Robert Collins
Actually make this branch work.
465
        reference_format = self.get_repo_format()
466
        network_name = reference_format.network_name()
3104.4.2 by Andrew Bennetts
All tests passing.
467
        transport = MemoryTransport()
468
        transport.mkdir('quack')
469
        transport = transport.clone('quack')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
470
        if rich_root:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
471
            rich_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
472
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
473
            rich_response = 'no'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
474
        if subtrees:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
475
            subtree_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
476
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
477
            subtree_response = 'no'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
478
        client = FakeClient(transport.base)
479
        client.add_success_response(
4053.1.2 by Robert Collins
Actually make this branch work.
480
            'ok', '', rich_response, subtree_response, external_lookup,
481
            network_name)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
482
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
483
            _client=client)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
484
        result = bzrdir.open_repository()
485
        self.assertEqual(
4053.1.2 by Robert Collins
Actually make this branch work.
486
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
487
            client._calls)
488
        self.assertIsInstance(result, RemoteRepository)
489
        self.assertEqual(bzrdir, result.bzrdir)
490
        self.assertEqual(rich_root, result._format.rich_root_data)
2018.5.138 by Robert Collins
Merge bzr.dev.
491
        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.
492
493
    def test_open_repository_sets_format_attributes(self):
494
        self.check_open_repository(True, True)
495
        self.check_open_repository(False, True)
496
        self.check_open_repository(True, False)
497
        self.check_open_repository(False, False)
3221.3.3 by Robert Collins
* Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
498
        self.check_open_repository(False, False, 'yes')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
499
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
500
    def test_old_server(self):
501
        """RemoteBzrDirFormat should fail to probe if the server version is too
502
        old.
503
        """
504
        self.assertRaises(errors.NotBranchError,
505
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
506
507
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
508
class TestBzrDirCreateBranch(TestRemote):
509
510
    def test_backwards_compat(self):
511
        self.setup_smart_server_with_call_log()
512
        repo = self.make_repository('.')
513
        self.reset_smart_call_log()
514
        self.disable_verb('BzrDir.create_branch')
515
        branch = repo.bzrdir.create_branch()
516
        create_branch_call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
517
            call.call.method == 'BzrDir.create_branch'])
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
518
        self.assertEqual(1, create_branch_call_count)
519
520
    def test_current_server(self):
521
        transport = self.get_transport('.')
522
        transport = transport.clone('quack')
523
        self.make_repository('quack')
524
        client = FakeClient(transport.base)
525
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
526
        reference_format = reference_bzrdir_format.get_branch_format()
527
        network_name = reference_format.network_name()
528
        reference_repo_fmt = reference_bzrdir_format.repository_format
529
        reference_repo_name = reference_repo_fmt.network_name()
530
        client.add_expected_call(
531
            'BzrDir.create_branch', ('quack/', network_name),
532
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
533
            reference_repo_name))
534
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
535
            _client=client)
536
        branch = a_bzrdir.create_branch()
537
        # We should have got a remote branch
538
        self.assertIsInstance(branch, remote.RemoteBranch)
539
        # its format should have the settings from the response
540
        format = branch._format
541
        self.assertEqual(network_name, format.network_name())
542
543
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
544
class TestBzrDirCreateRepository(TestRemote):
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
545
546
    def test_backwards_compat(self):
547
        self.setup_smart_server_with_call_log()
548
        bzrdir = self.make_bzrdir('.')
549
        self.reset_smart_call_log()
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
550
        self.disable_verb('BzrDir.create_repository')
551
        repo = bzrdir.create_repository()
552
        create_repo_call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
553
            call.call.method == 'BzrDir.create_repository'])
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
554
        self.assertEqual(1, create_repo_call_count)
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
555
556
    def test_current_server(self):
557
        transport = self.get_transport('.')
558
        transport = transport.clone('quack')
559
        self.make_bzrdir('quack')
560
        client = FakeClient(transport.base)
561
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
562
        reference_format = reference_bzrdir_format.repository_format
563
        network_name = reference_format.network_name()
564
        client.add_expected_call(
565
            'BzrDir.create_repository', ('quack/',
566
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
567
            'success', ('ok', 'no', 'no', 'no', network_name))
568
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
569
            _client=client)
570
        repo = a_bzrdir.create_repository()
571
        # We should have got a remote repository
572
        self.assertIsInstance(repo, remote.RemoteRepository)
573
        # its format should have the settings from the response
574
        format = repo._format
575
        self.assertFalse(format.rich_root_data)
576
        self.assertFalse(format.supports_tree_reference)
577
        self.assertFalse(format.supports_external_lookups)
578
        self.assertEqual(network_name, format.network_name())
579
580
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
581
class TestBzrDirOpenRepository(TestRemote):
582
583
    def test_backwards_compat_1_2_3(self):
584
        # fallback all the way to the first version.
585
        reference_format = self.get_repo_format()
586
        network_name = reference_format.network_name()
587
        client = FakeClient('bzr://example.com/')
588
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
589
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
590
        client.add_success_response('ok', '', 'no', 'no')
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
591
        # A real repository instance will be created to determine the network
592
        # name.
593
        client.add_success_response_with_body(
594
            "Bazaar-NG meta directory, format 1\n", 'ok')
595
        client.add_success_response_with_body(
596
            reference_format.get_format_string(), 'ok')
597
        # PackRepository wants to do a stat
598
        client.add_success_response('stat', '0', '65535')
599
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
600
            _client=client)
601
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
602
            _client=client)
603
        repo = bzrdir.open_repository()
604
        self.assertEqual(
605
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
606
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
607
             ('call', 'BzrDir.find_repository', ('quack/',)),
608
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
609
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
610
             ('call', 'stat', ('/quack/.bzr/repository',)),
611
             ],
612
            client._calls)
613
        self.assertEqual(network_name, repo._format.network_name())
614
615
    def test_backwards_compat_2(self):
616
        # fallback to find_repositoryV2
617
        reference_format = self.get_repo_format()
618
        network_name = reference_format.network_name()
619
        client = FakeClient('bzr://example.com/')
620
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
621
        client.add_success_response('ok', '', 'no', 'no', 'no')
622
        # A real repository instance will be created to determine the network
623
        # name.
624
        client.add_success_response_with_body(
625
            "Bazaar-NG meta directory, format 1\n", 'ok')
626
        client.add_success_response_with_body(
627
            reference_format.get_format_string(), 'ok')
628
        # PackRepository wants to do a stat
629
        client.add_success_response('stat', '0', '65535')
630
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
631
            _client=client)
632
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
633
            _client=client)
634
        repo = bzrdir.open_repository()
635
        self.assertEqual(
636
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
637
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
638
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
639
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
640
             ('call', 'stat', ('/quack/.bzr/repository',)),
641
             ],
642
            client._calls)
643
        self.assertEqual(network_name, repo._format.network_name())
644
645
    def test_current_server(self):
646
        reference_format = self.get_repo_format()
647
        network_name = reference_format.network_name()
648
        transport = MemoryTransport()
649
        transport.mkdir('quack')
650
        transport = transport.clone('quack')
651
        client = FakeClient(transport.base)
652
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
653
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
654
            _client=client)
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
655
        repo = bzrdir.open_repository()
656
        self.assertEqual(
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
657
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
658
            client._calls)
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
659
        self.assertEqual(network_name, repo._format.network_name())
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
660
661
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
662
class OldSmartClient(object):
663
    """A fake smart client for test_old_version that just returns a version one
664
    response to the 'hello' (query version) command.
665
    """
666
667
    def get_request(self):
668
        input_file = StringIO('ok\x011\n')
669
        output_file = StringIO()
670
        client_medium = medium.SmartSimplePipesClientMedium(
671
            input_file, output_file)
672
        return medium.SmartClientStreamMediumRequest(client_medium)
673
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
674
    def protocol_version(self):
675
        return 1
676
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
677
678
class OldServerTransport(object):
679
    """A fake transport for test_old_server that reports it's smart server
680
    protocol version as version one.
681
    """
682
683
    def __init__(self):
684
        self.base = 'fake:'
685
686
    def get_smart_client(self):
687
        return OldSmartClient()
688
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
689
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
690
class RemoteBranchTestCase(tests.TestCase):
691
692
    def make_remote_branch(self, transport, client):
693
        """Make a RemoteBranch using 'client' as its _SmartClient.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
694
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
695
        A RemoteBzrDir and RemoteRepository will also be created to fill out
696
        the RemoteBranch, albeit with stub values for some of their attributes.
697
        """
698
        # we do not want bzrdir to make any remote calls, so use False as its
699
        # _client.  If it tries to make a remote call, this will fail
700
        # immediately.
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
701
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
702
            _client=False)
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
703
        repo = RemoteRepository(bzrdir, None, _client=client)
704
        return RemoteBranch(bzrdir, repo, _client=client)
705
706
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
707
class TestBranchGetParent(RemoteBranchTestCase):
708
709
    def test_no_parent(self):
710
        # in an empty branch we decode the response properly
711
        transport = MemoryTransport()
712
        client = FakeClient(transport.base)
713
        client.add_expected_call(
714
            'Branch.get_stacked_on_url', ('quack/',),
715
            'error', ('NotStacked',))
716
        client.add_expected_call(
717
            'Branch.get_parent', ('quack/',),
718
            'success', (''))
719
        transport.mkdir('quack')
720
        transport = transport.clone('quack')
721
        branch = self.make_remote_branch(transport, client)
722
        result = branch.get_parent()
723
        client.finished_test()
724
        self.assertEqual(None, result)
725
726
    def test_parent_relative(self):
727
        transport = MemoryTransport()
728
        client = FakeClient(transport.base)
729
        client.add_expected_call(
730
            'Branch.get_stacked_on_url', ('kwaak/',),
731
            'error', ('NotStacked',))
732
        client.add_expected_call(
733
            'Branch.get_parent', ('kwaak/',),
734
            'success', ('../foo/'))
735
        transport.mkdir('kwaak')
736
        transport = transport.clone('kwaak')
737
        branch = self.make_remote_branch(transport, client)
738
        result = branch.get_parent()
739
        self.assertEqual(transport.clone('../foo').base, result)
740
741
    def test_parent_absolute(self):
742
        transport = MemoryTransport()
743
        client = FakeClient(transport.base)
744
        client.add_expected_call(
745
            'Branch.get_stacked_on_url', ('kwaak/',),
746
            'error', ('NotStacked',))
747
        client.add_expected_call(
748
            'Branch.get_parent', ('kwaak/',),
749
            'success', ('http://foo/'))
750
        transport.mkdir('kwaak')
751
        transport = transport.clone('kwaak')
752
        branch = self.make_remote_branch(transport, client)
753
        result = branch.get_parent()
754
        self.assertEqual('http://foo/', result)
755
756
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
757
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
758
759
    def test_empty_branch(self):
760
        # in an empty branch we decode the response properly
761
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
762
        client = FakeClient(transport.base)
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
763
        client.add_expected_call(
764
            'Branch.get_stacked_on_url', ('quack/',),
765
            'error', ('NotStacked',))
766
        client.add_expected_call(
767
            'Branch.last_revision_info', ('quack/',),
768
            'success', ('ok', '0', 'null:'))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
769
        transport.mkdir('quack')
770
        transport = transport.clone('quack')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
771
        branch = self.make_remote_branch(transport, client)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
772
        result = branch.last_revision_info()
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
773
        client.finished_test()
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
774
        self.assertEqual((0, NULL_REVISION), result)
775
776
    def test_non_empty_branch(self):
777
        # 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.
778
        revid = u'\xc8'.encode('utf8')
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
779
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
780
        client = FakeClient(transport.base)
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
781
        client.add_expected_call(
782
            'Branch.get_stacked_on_url', ('kwaak/',),
783
            'error', ('NotStacked',))
784
        client.add_expected_call(
785
            'Branch.last_revision_info', ('kwaak/',),
786
            'success', ('ok', '2', revid))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
787
        transport.mkdir('kwaak')
788
        transport = transport.clone('kwaak')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
789
        branch = self.make_remote_branch(transport, client)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
790
        result = branch.last_revision_info()
2018.5.106 by Andrew Bennetts
Update tests in test_remote to use utf-8 byte strings for revision IDs, rather than unicode strings.
791
        self.assertEqual((2, revid), result)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
792
793
4053.1.2 by Robert Collins
Actually make this branch work.
794
class TestBranch_get_stacked_on_url(TestRemote):
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
795
    """Test Branch._get_stacked_on_url rpc"""
796
3691.2.10 by Martin Pool
Update more test_remote tests
797
    def test_get_stacked_on_invalid_url(self):
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
798
        # test that asking for a stacked on url the server can't access works.
799
        # This isn't perfect, but then as we're in the same process there
800
        # really isn't anything we can do to be 100% sure that the server
801
        # doesn't just open in - this test probably needs to be rewritten using
802
        # a spawn()ed server.
803
        stacked_branch = self.make_branch('stacked', format='1.9')
804
        memory_branch = self.make_branch('base', format='1.9')
805
        vfs_url = self.get_vfs_only_url('base')
806
        stacked_branch.set_stacked_on_url(vfs_url)
807
        transport = stacked_branch.bzrdir.root_transport
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
808
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
809
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
810
            'Branch.get_stacked_on_url', ('stacked/',),
811
            'success', ('ok', vfs_url))
812
        # XXX: Multiple calls are bad, this second call documents what is
813
        # today.
814
        client.add_expected_call(
815
            'Branch.get_stacked_on_url', ('stacked/',),
816
            'success', ('ok', vfs_url))
817
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
818
            _client=client)
819
        branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, None),
820
            _client=client)
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
821
        result = branch.get_stacked_on_url()
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
822
        self.assertEqual(vfs_url, result)
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
823
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
824
    def test_backwards_compatible(self):
825
        # like with bzr1.6 with no Branch.get_stacked_on_url rpc
826
        base_branch = self.make_branch('base', format='1.6')
827
        stacked_branch = self.make_branch('stacked', format='1.6')
828
        stacked_branch.set_stacked_on_url('../base')
829
        client = FakeClient(self.get_url())
830
        client.add_expected_call(
831
            'BzrDir.open_branch', ('stacked/',),
832
            'success', ('ok', ''))
833
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
834
            'BzrDir.find_repositoryV3', ('stacked/',),
835
            'success', ('ok', '', 'no', 'no', 'no',
836
                stacked_branch.repository._format.network_name()))
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
837
        # called twice, once from constructor and then again by us
838
        client.add_expected_call(
839
            'Branch.get_stacked_on_url', ('stacked/',),
840
            'unknown', ('Branch.get_stacked_on_url',))
841
        client.add_expected_call(
842
            'Branch.get_stacked_on_url', ('stacked/',),
843
            'unknown', ('Branch.get_stacked_on_url',))
844
        # this will also do vfs access, but that goes direct to the transport
845
        # and isn't seen by the FakeClient.
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
846
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
847
            remote.RemoteBzrDirFormat(), _client=client)
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
848
        branch = bzrdir.open_branch()
849
        result = branch.get_stacked_on_url()
850
        self.assertEqual('../base', result)
851
        client.finished_test()
852
        # it's in the fallback list both for the RemoteRepository and its vfs
853
        # repository
854
        self.assertEqual(1, len(branch.repository._fallback_repositories))
855
        self.assertEqual(1,
856
            len(branch.repository._real_repository._fallback_repositories))
857
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
858
    def test_get_stacked_on_real_branch(self):
859
        base_branch = self.make_branch('base', format='1.6')
860
        stacked_branch = self.make_branch('stacked', format='1.6')
861
        stacked_branch.set_stacked_on_url('../base')
4053.1.2 by Robert Collins
Actually make this branch work.
862
        reference_format = self.get_repo_format()
863
        network_name = reference_format.network_name()
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
864
        client = FakeClient(self.get_url())
865
        client.add_expected_call(
866
            'BzrDir.open_branch', ('stacked/',),
867
            'success', ('ok', ''))
868
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
869
            'BzrDir.find_repositoryV3', ('stacked/',),
870
            'success', ('ok', '', 'no', 'no', 'no', network_name))
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
871
        # called twice, once from constructor and then again by us
872
        client.add_expected_call(
873
            'Branch.get_stacked_on_url', ('stacked/',),
874
            'success', ('ok', '../base'))
875
        client.add_expected_call(
876
            'Branch.get_stacked_on_url', ('stacked/',),
877
            'success', ('ok', '../base'))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
878
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
879
            remote.RemoteBzrDirFormat(), _client=client)
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
880
        branch = bzrdir.open_branch()
881
        result = branch.get_stacked_on_url()
882
        self.assertEqual('../base', result)
883
        client.finished_test()
884
        # it's in the fallback list both for the RemoteRepository and its vfs
885
        # repository
886
        self.assertEqual(1, len(branch.repository._fallback_repositories))
887
        self.assertEqual(1,
888
            len(branch.repository._real_repository._fallback_repositories))
889
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
890
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
891
class TestBranchSetLastRevision(RemoteBranchTestCase):
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
892
893
    def test_set_empty(self):
894
        # set_revision_history([]) is translated to calling
895
        # Branch.set_last_revision(path, '') on the wire.
3104.4.2 by Andrew Bennetts
All tests passing.
896
        transport = MemoryTransport()
897
        transport.mkdir('branch')
898
        transport = transport.clone('branch')
899
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
900
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
901
        client.add_expected_call(
902
            'Branch.get_stacked_on_url', ('branch/',),
903
            'error', ('NotStacked',))
904
        client.add_expected_call(
905
            'Branch.lock_write', ('branch/', '', ''),
906
            'success', ('ok', 'branch token', 'repo token'))
907
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
908
            'Branch.last_revision_info',
909
            ('branch/',),
910
            'success', ('ok', '0', 'null:'))
911
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
912
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
913
            'success', ('ok',))
914
        client.add_expected_call(
915
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
916
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
917
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
918
        # This is a hack to work around the problem that RemoteBranch currently
919
        # unnecessarily invokes _ensure_real upon a call to lock_write.
920
        branch._ensure_real = lambda: None
921
        branch.lock_write()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
922
        result = branch.set_revision_history([])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
923
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
924
        self.assertEqual(None, result)
3691.2.10 by Martin Pool
Update more test_remote tests
925
        client.finished_test()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
926
927
    def test_set_nonempty(self):
928
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
929
        # Branch.set_last_revision(path, rev-idN) on the wire.
3104.4.2 by Andrew Bennetts
All tests passing.
930
        transport = MemoryTransport()
931
        transport.mkdir('branch')
932
        transport = transport.clone('branch')
933
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
934
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
935
        client.add_expected_call(
936
            'Branch.get_stacked_on_url', ('branch/',),
937
            'error', ('NotStacked',))
938
        client.add_expected_call(
939
            'Branch.lock_write', ('branch/', '', ''),
940
            'success', ('ok', 'branch token', 'repo token'))
941
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
942
            'Branch.last_revision_info',
943
            ('branch/',),
944
            'success', ('ok', '0', 'null:'))
945
        lines = ['rev-id2']
946
        encoded_body = bz2.compress('\n'.join(lines))
947
        client.add_success_response_with_body(encoded_body, 'ok')
948
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
949
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
950
            'success', ('ok',))
951
        client.add_expected_call(
952
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
953
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
954
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
955
        # This is a hack to work around the problem that RemoteBranch currently
956
        # unnecessarily invokes _ensure_real upon a call to lock_write.
957
        branch._ensure_real = lambda: None
958
        # Lock the branch, reset the record of remote calls.
959
        branch.lock_write()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
960
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
961
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
962
        self.assertEqual(None, result)
3691.2.10 by Martin Pool
Update more test_remote tests
963
        client.finished_test()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
964
965
    def test_no_such_revision(self):
966
        transport = MemoryTransport()
967
        transport.mkdir('branch')
968
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
969
        # A response of 'NoSuchRevision' is translated into an exception.
970
        client = FakeClient(transport.base)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
971
        client.add_expected_call(
972
            'Branch.get_stacked_on_url', ('branch/',),
973
            'error', ('NotStacked',))
974
        client.add_expected_call(
975
            'Branch.lock_write', ('branch/', '', ''),
976
            'success', ('ok', 'branch token', 'repo token'))
977
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
978
            'Branch.last_revision_info',
979
            ('branch/',),
980
            'success', ('ok', '0', 'null:'))
981
        # get_graph calls to construct the revision history, for the set_rh
982
        # hook
983
        lines = ['rev-id']
984
        encoded_body = bz2.compress('\n'.join(lines))
985
        client.add_success_response_with_body(encoded_body, 'ok')
986
        client.add_expected_call(
3691.2.9 by Martin Pool
Convert and update more test_remote tests
987
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
988
            'error', ('NoSuchRevision', 'rev-id'))
989
        client.add_expected_call(
990
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
991
            'success', ('ok',))
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
992
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
993
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
994
        branch.lock_write()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
995
        self.assertRaises(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
996
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
997
        branch.unlock()
3691.2.9 by Martin Pool
Convert and update more test_remote tests
998
        client.finished_test()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
999
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1000
    def test_tip_change_rejected(self):
1001
        """TipChangeRejected responses cause a TipChangeRejected exception to
1002
        be raised.
1003
        """
1004
        transport = MemoryTransport()
1005
        transport.mkdir('branch')
1006
        transport = transport.clone('branch')
1007
        client = FakeClient(transport.base)
1008
        rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1009
        rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
3691.2.10 by Martin Pool
Update more test_remote tests
1010
        client.add_expected_call(
1011
            'Branch.get_stacked_on_url', ('branch/',),
1012
            'error', ('NotStacked',))
1013
        client.add_expected_call(
1014
            'Branch.lock_write', ('branch/', '', ''),
1015
            'success', ('ok', 'branch token', 'repo token'))
1016
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1017
            'Branch.last_revision_info',
1018
            ('branch/',),
1019
            'success', ('ok', '0', 'null:'))
1020
        lines = ['rev-id']
1021
        encoded_body = bz2.compress('\n'.join(lines))
1022
        client.add_success_response_with_body(encoded_body, 'ok')
1023
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1024
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1025
            'error', ('TipChangeRejected', rejection_msg_utf8))
1026
        client.add_expected_call(
1027
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1028
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1029
        branch = self.make_remote_branch(transport, client)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1030
        branch._ensure_real = lambda: None
1031
        branch.lock_write()
1032
        # The 'TipChangeRejected' error response triggered by calling
1033
        # set_revision_history causes a TipChangeRejected exception.
1034
        err = self.assertRaises(
1035
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1036
        # The UTF-8 message from the response has been decoded into a unicode
1037
        # object.
1038
        self.assertIsInstance(err.msg, unicode)
1039
        self.assertEqual(rejection_msg_unicode, err.msg)
3691.2.10 by Martin Pool
Update more test_remote tests
1040
        branch.unlock()
1041
        client.finished_test()
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1042
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
1043
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1044
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1045
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1046
    def test_set_last_revision_info(self):
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1047
        # set_last_revision_info(num, 'rev-id') is translated to calling
1048
        # Branch.set_last_revision_info(num, 'rev-id') on the wire.
3297.4.1 by Andrew Bennetts
Merge 'Add Branch.set_last_revision_info smart method'.
1049
        transport = MemoryTransport()
1050
        transport.mkdir('branch')
1051
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1052
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1053
        # get_stacked_on_url
1054
        client.add_error_response('NotStacked')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1055
        # lock_write
1056
        client.add_success_response('ok', 'branch token', 'repo token')
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1057
        # query the current revision
1058
        client.add_success_response('ok', '0', 'null:')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1059
        # set_last_revision
1060
        client.add_success_response('ok')
1061
        # unlock
1062
        client.add_success_response('ok')
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1063
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1064
        branch = self.make_remote_branch(transport, client)
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1065
        # Lock the branch, reset the record of remote calls.
1066
        branch.lock_write()
1067
        client._calls = []
1068
        result = branch.set_last_revision_info(1234, 'a-revision-id')
1069
        self.assertEqual(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1070
            [('call', 'Branch.last_revision_info', ('branch/',)),
1071
             ('call', 'Branch.set_last_revision_info',
3297.4.1 by Andrew Bennetts
Merge 'Add Branch.set_last_revision_info smart method'.
1072
                ('branch/', 'branch token', 'repo token',
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1073
                 '1234', 'a-revision-id'))],
1074
            client._calls)
1075
        self.assertEqual(None, result)
1076
1077
    def test_no_such_revision(self):
1078
        # A response of 'NoSuchRevision' is translated into an exception.
1079
        transport = MemoryTransport()
1080
        transport.mkdir('branch')
1081
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1082
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1083
        # get_stacked_on_url
1084
        client.add_error_response('NotStacked')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1085
        # lock_write
1086
        client.add_success_response('ok', 'branch token', 'repo token')
1087
        # set_last_revision
1088
        client.add_error_response('NoSuchRevision', 'revid')
1089
        # unlock
1090
        client.add_success_response('ok')
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1091
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1092
        branch = self.make_remote_branch(transport, client)
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1093
        # Lock the branch, reset the record of remote calls.
1094
        branch.lock_write()
1095
        client._calls = []
1096
1097
        self.assertRaises(
1098
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1099
        branch.unlock()
1100
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1101
    def lock_remote_branch(self, branch):
1102
        """Trick a RemoteBranch into thinking it is locked."""
1103
        branch._lock_mode = 'w'
1104
        branch._lock_count = 2
1105
        branch._lock_token = 'branch token'
1106
        branch._repo_lock_token = 'repo token'
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1107
        branch.repository._lock_mode = 'w'
1108
        branch.repository._lock_count = 2
1109
        branch.repository._lock_token = 'repo token'
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1110
1111
    def test_backwards_compatibility(self):
1112
        """If the server does not support the Branch.set_last_revision_info
1113
        verb (which is new in 1.4), then the client falls back to VFS methods.
1114
        """
1115
        # This test is a little messy.  Unlike most tests in this file, it
1116
        # doesn't purely test what a Remote* object sends over the wire, and
1117
        # how it reacts to responses from the wire.  It instead relies partly
1118
        # on asserting that the RemoteBranch will call
1119
        # self._real_branch.set_last_revision_info(...).
1120
1121
        # First, set up our RemoteBranch with a FakeClient that raises
1122
        # UnknownSmartMethod, and a StubRealBranch that logs how it is called.
1123
        transport = MemoryTransport()
1124
        transport.mkdir('branch')
1125
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1126
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1127
        client.add_expected_call(
1128
            'Branch.get_stacked_on_url', ('branch/',),
1129
            'error', ('NotStacked',))
1130
        client.add_expected_call(
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1131
            'Branch.last_revision_info',
1132
            ('branch/',),
1133
            'success', ('ok', '0', 'null:'))
1134
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1135
            'Branch.set_last_revision_info',
1136
            ('branch/', 'branch token', 'repo token', '1234', 'a-revision-id',),
1137
            'unknown', 'Branch.set_last_revision_info')
1138
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1139
        branch = self.make_remote_branch(transport, client)
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1140
        class StubRealBranch(object):
1141
            def __init__(self):
1142
                self.calls = []
1143
            def set_last_revision_info(self, revno, revision_id):
1144
                self.calls.append(
1145
                    ('set_last_revision_info', revno, revision_id))
3441.5.5 by Andrew Bennetts
Some small tweaks and comments.
1146
            def _clear_cached_state(self):
1147
                pass
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1148
        real_branch = StubRealBranch()
1149
        branch._real_branch = real_branch
1150
        self.lock_remote_branch(branch)
1151
1152
        # Call set_last_revision_info, and verify it behaved as expected.
1153
        result = branch.set_last_revision_info(1234, 'a-revision-id')
1154
        self.assertEqual(
1155
            [('set_last_revision_info', 1234, 'a-revision-id')],
1156
            real_branch.calls)
3691.2.10 by Martin Pool
Update more test_remote tests
1157
        client.finished_test()
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1158
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1159
    def test_unexpected_error(self):
3697.2.6 by Martin Pool
Merge 261315 fix into 1.7 branch
1160
        # If the server sends an error the client doesn't understand, it gets
1161
        # turned into an UnknownErrorFromSmartServer, which is presented as a
1162
        # non-internal error to the user.
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1163
        transport = MemoryTransport()
1164
        transport.mkdir('branch')
1165
        transport = transport.clone('branch')
1166
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1167
        # get_stacked_on_url
1168
        client.add_error_response('NotStacked')
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1169
        # lock_write
1170
        client.add_success_response('ok', 'branch token', 'repo token')
1171
        # set_last_revision
1172
        client.add_error_response('UnexpectedError')
1173
        # unlock
1174
        client.add_success_response('ok')
1175
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1176
        branch = self.make_remote_branch(transport, client)
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1177
        # Lock the branch, reset the record of remote calls.
1178
        branch.lock_write()
1179
        client._calls = []
1180
1181
        err = self.assertRaises(
3690.1.2 by Andrew Bennetts
Rename UntranslateableErrorFromSmartServer -> UnknownErrorFromSmartServer.
1182
            errors.UnknownErrorFromSmartServer,
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1183
            branch.set_last_revision_info, 123, 'revid')
1184
        self.assertEqual(('UnexpectedError',), err.error_tuple)
1185
        branch.unlock()
1186
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1187
    def test_tip_change_rejected(self):
1188
        """TipChangeRejected responses cause a TipChangeRejected exception to
1189
        be raised.
1190
        """
1191
        transport = MemoryTransport()
1192
        transport.mkdir('branch')
1193
        transport = transport.clone('branch')
1194
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1195
        # get_stacked_on_url
1196
        client.add_error_response('NotStacked')
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1197
        # lock_write
1198
        client.add_success_response('ok', 'branch token', 'repo token')
1199
        # set_last_revision
1200
        client.add_error_response('TipChangeRejected', 'rejection message')
1201
        # unlock
1202
        client.add_success_response('ok')
1203
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1204
        branch = self.make_remote_branch(transport, client)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1205
        # Lock the branch, reset the record of remote calls.
1206
        branch.lock_write()
1207
        self.addCleanup(branch.unlock)
1208
        client._calls = []
1209
1210
        # The 'TipChangeRejected' error response triggered by calling
1211
        # set_last_revision_info causes a TipChangeRejected exception.
1212
        err = self.assertRaises(
1213
            errors.TipChangeRejected,
1214
            branch.set_last_revision_info, 123, 'revid')
1215
        self.assertEqual('rejection message', err.msg)
1216
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1217
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.
1218
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
3408.3.1 by Martin Pool
Remove erroneous handling of branch.conf for RemoteBranch
1219
    """Getting the branch configuration should use an abstract method not vfs.
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
1220
    """
1221
1222
    def test_get_branch_conf(self):
3408.3.1 by Martin Pool
Remove erroneous handling of branch.conf for RemoteBranch
1223
        raise tests.KnownFailure('branch.conf is not retrieved by get_config_file')
3407.2.10 by Martin Pool
Merge trunk
1224
        ## # We should see that branch.get_config() does a single rpc to get the
1225
        ## # remote configuration file, abstracting away where that is stored on
1226
        ## # the server.  However at the moment it always falls back to using the
1227
        ## # vfs, and this would need some changes in config.py.
3408.3.1 by Martin Pool
Remove erroneous handling of branch.conf for RemoteBranch
1228
3407.2.10 by Martin Pool
Merge trunk
1229
        ## # in an empty branch we decode the response properly
1230
        ## client = FakeClient([(('ok', ), '# config file body')], self.get_url())
1231
        ## # we need to make a real branch because the remote_branch.control_files
1232
        ## # will trigger _ensure_real.
1233
        ## branch = self.make_branch('quack')
1234
        ## transport = branch.bzrdir.root_transport
1235
        ## # we do not want bzrdir to make any remote calls
1236
        ## bzrdir = RemoteBzrDir(transport, _client=False)
1237
        ## branch = RemoteBranch(bzrdir, None, _client=client)
1238
        ## config = branch.get_config()
1239
        ## self.assertEqual(
1240
        ##     [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
1241
        ##     client._calls)
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
1242
1243
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1244
class TestBranchLockWrite(RemoteBranchTestCase):
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.
1245
1246
    def test_lock_write_unlockable(self):
1247
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1248
        client = FakeClient(transport.base)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1249
        client.add_expected_call(
1250
            'Branch.get_stacked_on_url', ('quack/',),
1251
            'error', ('NotStacked',),)
1252
        client.add_expected_call(
1253
            'Branch.lock_write', ('quack/', '', ''),
1254
            'error', ('UnlockableTransport',))
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.
1255
        transport.mkdir('quack')
1256
        transport = transport.clone('quack')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1257
        branch = self.make_remote_branch(transport, client)
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.
1258
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1259
        client.finished_test()
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.
1260
1261
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1262
class TestTransportIsReadonly(tests.TestCase):
1263
1264
    def test_true(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1265
        client = FakeClient()
1266
        client.add_success_response('yes')
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1267
        transport = RemoteTransport('bzr://example.com/', medium=False,
1268
                                    _client=client)
1269
        self.assertEqual(True, transport.is_readonly())
1270
        self.assertEqual(
1271
            [('call', 'Transport.is_readonly', ())],
1272
            client._calls)
1273
1274
    def test_false(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1275
        client = FakeClient()
1276
        client.add_success_response('no')
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1277
        transport = RemoteTransport('bzr://example.com/', medium=False,
1278
                                    _client=client)
1279
        self.assertEqual(False, transport.is_readonly())
1280
        self.assertEqual(
1281
            [('call', 'Transport.is_readonly', ())],
1282
            client._calls)
1283
1284
    def test_error_from_old_server(self):
1285
        """bzr 0.15 and earlier servers don't recognise the is_readonly verb.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1286
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1287
        Clients should treat it as a "no" response, because is_readonly is only
1288
        advisory anyway (a transport could be read-write, but then the
1289
        underlying filesystem could be readonly anyway).
1290
        """
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1291
        client = FakeClient()
1292
        client.add_unknown_method_response('Transport.is_readonly')
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.
1293
        transport = RemoteTransport('bzr://example.com/', medium=False,
1294
                                    _client=client)
1295
        self.assertEqual(False, transport.is_readonly())
1296
        self.assertEqual(
1297
            [('call', 'Transport.is_readonly', ())],
1298
            client._calls)
1299
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1300
3840.1.1 by Andrew Bennetts
Fix RemoteTransport's translation of errors involving paths; it wasn't passing orig_path to _translate_error.
1301
class TestTransportMkdir(tests.TestCase):
1302
1303
    def test_permissiondenied(self):
1304
        client = FakeClient()
1305
        client.add_error_response('PermissionDenied', 'remote path', 'extra')
1306
        transport = RemoteTransport('bzr://example.com/', medium=False,
1307
                                    _client=client)
1308
        exc = self.assertRaises(
1309
            errors.PermissionDenied, transport.mkdir, 'client path')
1310
        expected_error = errors.PermissionDenied('/client path', 'extra')
1311
        self.assertEqual(expected_error, exc)
1312
1313
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
1314
class TestRemoteSSHTransportAuthentication(tests.TestCaseInTempDir):
1315
1316
    def test_defaults_to_none(self):
1317
        t = RemoteSSHTransport('bzr+ssh://example.com')
1318
        self.assertIs(None, t._get_credentials()[0])
1319
1320
    def test_uses_authentication_config(self):
1321
        conf = config.AuthenticationConfig()
1322
        conf._get_config().update(
1323
            {'bzr+sshtest': {'scheme': 'ssh', 'user': 'bar', 'host':
1324
            'example.com'}})
1325
        conf._save()
1326
        t = RemoteSSHTransport('bzr+ssh://example.com')
1327
        self.assertEqual('bar', t._get_credentials()[0])
1328
1329
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
1330
class TestRemoteRepository(TestRemote):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1331
    """Base for testing RemoteRepository protocol usage.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1332
1333
    These tests contain frozen requests and responses.  We want any changes to
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1334
    what is sent or expected to be require a thoughtful update to these tests
1335
    because they might break compatibility with different-versioned servers.
1336
    """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1337
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1338
    def setup_fake_client_and_repository(self, transport_path):
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1339
        """Create the fake client and repository for testing with.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1340
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1341
        There's no real server here; we just have canned responses sent
1342
        back one by one.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1343
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1344
        :param transport_path: Path below the root of the MemoryTransport
1345
            where the repository will be created.
1346
        """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1347
        transport = MemoryTransport()
1348
        transport.mkdir(transport_path)
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1349
        client = FakeClient(transport.base)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1350
        transport = transport.clone(transport_path)
1351
        # we do not want bzrdir to make any remote calls
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1352
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1353
            _client=False)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1354
        repo = RemoteRepository(bzrdir, None, _client=client)
1355
        return repo, client
1356
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1357
2018.12.2 by Andrew Bennetts
Remove some duplicate code in test_remote
1358
class TestRepositoryGatherStats(TestRemoteRepository):
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1359
1360
    def test_revid_none(self):
1361
        # ('ok',), body with revisions and size
1362
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1363
        repo, client = self.setup_fake_client_and_repository(transport_path)
1364
        client.add_success_response_with_body(
1365
            'revisions: 2\nsize: 18\n', 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1366
        result = repo.gather_stats(None)
1367
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1368
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1369
             ('quack/','','no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1370
            client._calls)
1371
        self.assertEqual({'revisions': 2, 'size': 18}, result)
1372
1373
    def test_revid_no_committers(self):
1374
        # ('ok',), body without committers
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1375
        body = ('firstrev: 123456.300 3600\n'
1376
                'latestrev: 654231.400 0\n'
1377
                'revisions: 2\n'
1378
                'size: 18\n')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1379
        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.
1380
        revid = u'\xc8'.encode('utf8')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1381
        repo, client = self.setup_fake_client_and_repository(transport_path)
1382
        client.add_success_response_with_body(body, 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1383
        result = repo.gather_stats(revid)
1384
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1385
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1386
              ('quick/', revid, 'no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1387
            client._calls)
1388
        self.assertEqual({'revisions': 2, 'size': 18,
1389
                          'firstrev': (123456.300, 3600),
1390
                          'latestrev': (654231.400, 0),},
1391
                         result)
1392
1393
    def test_revid_with_committers(self):
1394
        # ('ok',), body with committers
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1395
        body = ('committers: 128\n'
1396
                'firstrev: 123456.300 3600\n'
1397
                'latestrev: 654231.400 0\n'
1398
                'revisions: 2\n'
1399
                'size: 18\n')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1400
        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.
1401
        revid = u'\xc8'.encode('utf8')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1402
        repo, client = self.setup_fake_client_and_repository(transport_path)
1403
        client.add_success_response_with_body(body, 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1404
        result = repo.gather_stats(revid, True)
1405
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1406
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1407
              ('buick/', revid, 'yes'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1408
            client._calls)
1409
        self.assertEqual({'revisions': 2, 'size': 18,
1410
                          'committers': 128,
1411
                          'firstrev': (123456.300, 3600),
1412
                          'latestrev': (654231.400, 0),},
1413
                         result)
1414
1415
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1416
class TestRepositoryGetGraph(TestRemoteRepository):
1417
1418
    def test_get_graph(self):
3835.1.6 by Aaron Bentley
Reduce inefficiency when doing make_parents_provider frequently
1419
        # get_graph returns a graph with a custom parents provider.
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1420
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1421
        repo, client = self.setup_fake_client_and_repository(transport_path)
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1422
        graph = repo.get_graph()
3835.1.6 by Aaron Bentley
Reduce inefficiency when doing make_parents_provider frequently
1423
        self.assertNotEqual(graph._parents_provider, repo)
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1424
1425
1426
class TestRepositoryGetParentMap(TestRemoteRepository):
1427
1428
    def test_get_parent_map_caching(self):
1429
        # get_parent_map returns from cache until unlock()
1430
        # setup a reponse with two revisions
1431
        r1 = u'\u0e33'.encode('utf8')
1432
        r2 = u'\u0dab'.encode('utf8')
1433
        lines = [' '.join([r2, r1]), r1]
3211.5.2 by Robert Collins
Change RemoteRepository.get_parent_map to use bz2 not gzip for compression.
1434
        encoded_body = bz2.compress('\n'.join(lines))
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1435
1436
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1437
        repo, client = self.setup_fake_client_and_repository(transport_path)
1438
        client.add_success_response_with_body(encoded_body, 'ok')
1439
        client.add_success_response_with_body(encoded_body, 'ok')
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1440
        repo.lock_read()
1441
        graph = repo.get_graph()
1442
        parents = graph.get_parent_map([r2])
1443
        self.assertEqual({r2: (r1,)}, parents)
1444
        # locking and unlocking deeper should not reset
1445
        repo.lock_read()
1446
        repo.unlock()
1447
        parents = graph.get_parent_map([r1])
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
1448
        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.
1449
        self.assertEqual(
3211.5.1 by Robert Collins
Change the smart server get_parents method to take a graph search to exclude already recieved parents from. This prevents history shortcuts causing huge numbers of duplicates.
1450
            [('call_with_body_bytes_expecting_body',
1451
              'Repository.get_parent_map', ('quack/', r2), '\n\n0')],
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1452
            client._calls)
1453
        repo.unlock()
1454
        # now we call again, and it should use the second response.
1455
        repo.lock_read()
1456
        graph = repo.get_graph()
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
1457
        parents = graph.get_parent_map([r1])
1458
        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.
1459
        self.assertEqual(
3211.5.1 by Robert Collins
Change the smart server get_parents method to take a graph search to exclude already recieved parents from. This prevents history shortcuts causing huge numbers of duplicates.
1460
            [('call_with_body_bytes_expecting_body',
1461
              'Repository.get_parent_map', ('quack/', r2), '\n\n0'),
1462
             ('call_with_body_bytes_expecting_body',
1463
              'Repository.get_parent_map', ('quack/', r1), '\n\n0'),
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1464
            ],
1465
            client._calls)
1466
        repo.unlock()
1467
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1468
    def test_get_parent_map_reconnects_if_unknown_method(self):
1469
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1470
        repo, client = self.setup_fake_client_and_repository(transport_path)
3842.3.20 by Andrew Bennetts
Re-revert changes from another thread that accidentally got reinstated here.
1471
        client.add_unknown_method_response('Repository,get_parent_map')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1472
        client.add_success_response_with_body('', 'ok')
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
1473
        self.assertFalse(client._medium._is_remote_before((1, 2)))
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1474
        rev_id = 'revision-id'
3297.3.5 by Andrew Bennetts
Suppress a deprecation warning.
1475
        expected_deprecations = [
1476
            'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
1477
            'in version 1.4.']
1478
        parents = self.callDeprecated(
1479
            expected_deprecations, repo.get_parent_map, [rev_id])
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1480
        self.assertEqual(
3213.1.8 by Andrew Bennetts
Merge from bzr.dev.
1481
            [('call_with_body_bytes_expecting_body',
1482
              'Repository.get_parent_map', ('quack/', rev_id), '\n\n0'),
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1483
             ('disconnect medium',),
1484
             ('call_expecting_body', 'Repository.get_revision_graph',
1485
              ('quack/', ''))],
1486
            client._calls)
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1487
        # The medium is now marked as being connected to an older server
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
1488
        self.assertTrue(client._medium._is_remote_before((1, 2)))
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1489
1490
    def test_get_parent_map_fallback_parentless_node(self):
1491
        """get_parent_map falls back to get_revision_graph on old servers.  The
1492
        results from get_revision_graph are tweaked to match the get_parent_map
1493
        API.
1494
3389.1.3 by Andrew Bennetts
Remove XXX from test description.
1495
        Specifically, a {key: ()} result from get_revision_graph means "no
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1496
        parents" for that key, which in get_parent_map results should be
3389.1.3 by Andrew Bennetts
Remove XXX from test description.
1497
        represented as {key: ('null:',)}.
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1498
1499
        This is the test for https://bugs.launchpad.net/bzr/+bug/214894
1500
        """
1501
        rev_id = 'revision-id'
1502
        transport_path = 'quack'
3245.4.40 by Andrew Bennetts
Merge from bzr.dev.
1503
        repo, client = self.setup_fake_client_and_repository(transport_path)
1504
        client.add_success_response_with_body(rev_id, 'ok')
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
1505
        client._medium._remember_remote_is_before((1, 2))
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1506
        expected_deprecations = [
1507
            'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
1508
            'in version 1.4.']
1509
        parents = self.callDeprecated(
1510
            expected_deprecations, repo.get_parent_map, [rev_id])
1511
        self.assertEqual(
1512
            [('call_expecting_body', 'Repository.get_revision_graph',
1513
             ('quack/', ''))],
1514
            client._calls)
1515
        self.assertEqual({rev_id: ('null:',)}, parents)
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1516
3297.2.3 by Andrew Bennetts
Test the code path that the typo is on.
1517
    def test_get_parent_map_unexpected_response(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1518
        repo, client = self.setup_fake_client_and_repository('path')
1519
        client.add_success_response('something unexpected!')
3297.2.3 by Andrew Bennetts
Test the code path that the typo is on.
1520
        self.assertRaises(
1521
            errors.UnexpectedSmartServerResponse,
1522
            repo.get_parent_map, ['a-revision-id'])
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1523
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1524
3835.1.15 by Aaron Bentley
Allow miss caching to be disabled.
1525
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
1526
1527
    def test_allows_new_revisions(self):
1528
        """get_parent_map's results can be updated by commit."""
1529
        smart_server = server.SmartTCPServer_for_testing()
1530
        smart_server.setUp()
1531
        self.addCleanup(smart_server.tearDown)
1532
        self.make_branch('branch')
1533
        branch = Branch.open(smart_server.get_url() + '/branch')
1534
        tree = branch.create_checkout('tree', lightweight=True)
1535
        tree.lock_write()
1536
        self.addCleanup(tree.unlock)
1537
        graph = tree.branch.repository.get_graph()
1538
        # This provides an opportunity for the missing rev-id to be cached.
1539
        self.assertEqual({}, graph.get_parent_map(['rev1']))
1540
        tree.commit('message', rev_id='rev1')
1541
        graph = tree.branch.repository.get_graph()
1542
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
1543
1544
2018.5.68 by Wouter van Heyst
Merge RemoteRepository.gather_stats.
1545
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1546
2018.5.68 by Wouter van Heyst
Merge RemoteRepository.gather_stats.
1547
    def test_null_revision(self):
1548
        # a null revision has the predictable result {}, we should have no wire
1549
        # traffic when calling it with this argument
1550
        transport_path = 'empty'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1551
        repo, client = self.setup_fake_client_and_repository(transport_path)
1552
        client.add_success_response('notused')
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
1553
        result = self.applyDeprecated(one_four, repo.get_revision_graph,
1554
            NULL_REVISION)
2018.5.68 by Wouter van Heyst
Merge RemoteRepository.gather_stats.
1555
        self.assertEqual([], client._calls)
1556
        self.assertEqual({}, result)
1557
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1558
    def test_none_revision(self):
1559
        # 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.
1560
        r1 = u'\u0e33'.encode('utf8')
1561
        r2 = u'\u0dab'.encode('utf8')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1562
        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.
1563
        encoded_body = '\n'.join(lines)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1564
1565
        transport_path = 'sinhala'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1566
        repo, client = self.setup_fake_client_and_repository(transport_path)
1567
        client.add_success_response_with_body(encoded_body, 'ok')
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
1568
        result = self.applyDeprecated(one_four, repo.get_revision_graph)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1569
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1570
            [('call_expecting_body', 'Repository.get_revision_graph',
3104.4.2 by Andrew Bennetts
All tests passing.
1571
             ('sinhala/', ''))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1572
            client._calls)
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
1573
        self.assertEqual({r1: (), r2: (r1, )}, result)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1574
1575
    def test_specific_revision(self):
1576
        # with a specific revision we want the graph for that
1577
        # 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.
1578
        r11 = u'\u0e33'.encode('utf8')
1579
        r12 = u'\xc9'.encode('utf8')
1580
        r2 = u'\u0dab'.encode('utf8')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1581
        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.
1582
        encoded_body = '\n'.join(lines)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1583
1584
        transport_path = 'sinhala'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1585
        repo, client = self.setup_fake_client_and_repository(transport_path)
1586
        client.add_success_response_with_body(encoded_body, 'ok')
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
1587
        result = self.applyDeprecated(one_four, repo.get_revision_graph, r2)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1588
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1589
            [('call_expecting_body', 'Repository.get_revision_graph',
3104.4.2 by Andrew Bennetts
All tests passing.
1590
             ('sinhala/', r2))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1591
            client._calls)
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
1592
        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)
1593
1594
    def test_no_such_revision(self):
1595
        revid = '123'
1596
        transport_path = 'sinhala'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1597
        repo, client = self.setup_fake_client_and_repository(transport_path)
1598
        client.add_error_response('nosuchrevision', revid)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1599
        # 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
1600
        self.assertRaises(errors.NoSuchRevision,
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
1601
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1602
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1603
            [('call_expecting_body', 'Repository.get_revision_graph',
3104.4.2 by Andrew Bennetts
All tests passing.
1604
             ('sinhala/', revid))],
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1605
            client._calls)
1606
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1607
    def test_unexpected_error(self):
1608
        revid = '123'
1609
        transport_path = 'sinhala'
1610
        repo, client = self.setup_fake_client_and_repository(transport_path)
1611
        client.add_error_response('AnUnexpectedError')
3690.1.2 by Andrew Bennetts
Rename UntranslateableErrorFromSmartServer -> UnknownErrorFromSmartServer.
1612
        e = self.assertRaises(errors.UnknownErrorFromSmartServer,
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1613
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
1614
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
1615
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1616
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1617
class TestRepositoryIsShared(TestRemoteRepository):
1618
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1619
    def test_is_shared(self):
1620
        # ('yes', ) for Repository.is_shared -> 'True'.
1621
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1622
        repo, client = self.setup_fake_client_and_repository(transport_path)
1623
        client.add_success_response('yes')
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1624
        result = repo.is_shared()
1625
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1626
            [('call', 'Repository.is_shared', ('quack/',))],
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1627
            client._calls)
1628
        self.assertEqual(True, result)
1629
1630
    def test_is_not_shared(self):
1631
        # ('no', ) for Repository.is_shared -> 'False'.
1632
        transport_path = 'qwack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1633
        repo, client = self.setup_fake_client_and_repository(transport_path)
1634
        client.add_success_response('no')
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1635
        result = repo.is_shared()
1636
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1637
            [('call', 'Repository.is_shared', ('qwack/',))],
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1638
            client._calls)
1639
        self.assertEqual(False, result)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1640
1641
1642
class TestRepositoryLockWrite(TestRemoteRepository):
1643
1644
    def test_lock_write(self):
1645
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1646
        repo, client = self.setup_fake_client_and_repository(transport_path)
1647
        client.add_success_response('ok', 'a token')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1648
        result = repo.lock_write()
1649
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1650
            [('call', 'Repository.lock_write', ('quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1651
            client._calls)
1652
        self.assertEqual('a token', result)
1653
1654
    def test_lock_write_already_locked(self):
1655
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1656
        repo, client = self.setup_fake_client_and_repository(transport_path)
1657
        client.add_error_response('LockContention')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1658
        self.assertRaises(errors.LockContention, repo.lock_write)
1659
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1660
            [('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.
1661
            client._calls)
1662
1663
    def test_lock_write_unlockable(self):
1664
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1665
        repo, client = self.setup_fake_client_and_repository(transport_path)
1666
        client.add_error_response('UnlockableTransport')
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.
1667
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
1668
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1669
            [('call', 'Repository.lock_write', ('quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1670
            client._calls)
1671
1672
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
1673
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
1674
1675
    def test_backwards_compat(self):
1676
        self.setup_smart_server_with_call_log()
1677
        repo = self.make_repository('.')
1678
        self.reset_smart_call_log()
1679
        verb = 'Repository.set_make_working_trees'
1680
        self.disable_verb(verb)
1681
        repo.set_make_working_trees(True)
1682
        call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
1683
            call.call.method == verb])
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
1684
        self.assertEqual(1, call_count)
1685
1686
    def test_current(self):
1687
        transport_path = 'quack'
1688
        repo, client = self.setup_fake_client_and_repository(transport_path)
1689
        client.add_expected_call(
1690
            'Repository.set_make_working_trees', ('quack/', 'True'),
1691
            'success', ('ok',))
1692
        client.add_expected_call(
1693
            'Repository.set_make_working_trees', ('quack/', 'False'),
1694
            'success', ('ok',))
1695
        repo.set_make_working_trees(True)
1696
        repo.set_make_working_trees(False)
1697
1698
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1699
class TestRepositoryUnlock(TestRemoteRepository):
1700
1701
    def test_unlock(self):
1702
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1703
        repo, client = self.setup_fake_client_and_repository(transport_path)
1704
        client.add_success_response('ok', 'a token')
1705
        client.add_success_response('ok')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1706
        repo.lock_write()
1707
        repo.unlock()
1708
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
1709
            [('call', 'Repository.lock_write', ('quack/', '')),
1710
             ('call', 'Repository.unlock', ('quack/', 'a token'))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1711
            client._calls)
1712
1713
    def test_unlock_wrong_token(self):
1714
        # If somehow the token is wrong, unlock will raise TokenMismatch.
1715
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1716
        repo, client = self.setup_fake_client_and_repository(transport_path)
1717
        client.add_success_response('ok', 'a token')
1718
        client.add_error_response('TokenMismatch')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1719
        repo.lock_write()
1720
        self.assertRaises(errors.TokenMismatch, repo.unlock)
1721
1722
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1723
class TestRepositoryHasRevision(TestRemoteRepository):
1724
1725
    def test_none(self):
1726
        # repo.has_revision(None) should not cause any traffic.
1727
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1728
        repo, client = self.setup_fake_client_and_repository(transport_path)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1729
1730
        # The null revision is always there, so has_revision(None) == True.
3172.3.3 by Robert Collins
Missed one occurence of None -> NULL_REVISION.
1731
        self.assertEqual(True, repo.has_revision(NULL_REVISION))
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1732
1733
        # The remote repo shouldn't be accessed.
1734
        self.assertEqual([], client._calls)
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1735
1736
1737
class TestRepositoryTarball(TestRemoteRepository):
1738
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1739
    # This is a canned tarball reponse we can validate against
2018.18.18 by Martin Pool
reformat
1740
    tarball_content = (
2018.18.23 by Martin Pool
review cleanups
1741
        'QlpoOTFBWSZTWdGkj3wAAWF/k8aQACBIB//A9+8cIX/v33AACEAYABAECEACNz'
1742
        'JqsgJJFPTSnk1A3qh6mTQAAAANPUHkagkSTEkaA09QaNAAAGgAAAcwCYCZGAEY'
1743
        'mJhMJghpiaYBUkKammSHqNMZQ0NABkNAeo0AGneAevnlwQoGzEzNVzaYxp/1Uk'
1744
        'xXzA1CQX0BJMZZLcPBrluJir5SQyijWHYZ6ZUtVqqlYDdB2QoCwa9GyWwGYDMA'
1745
        'OQYhkpLt/OKFnnlT8E0PmO8+ZNSo2WWqeCzGB5fBXZ3IvV7uNJVE7DYnWj6qwB'
1746
        'k5DJDIrQ5OQHHIjkS9KqwG3mc3t+F1+iujb89ufyBNIKCgeZBWrl5cXxbMGoMs'
1747
        'c9JuUkg5YsiVcaZJurc6KLi6yKOkgCUOlIlOpOoXyrTJjK8ZgbklReDdwGmFgt'
1748
        'dkVsAIslSVCd4AtACSLbyhLHryfb14PKegrVDba+U8OL6KQtzdM5HLjAc8/p6n'
1749
        '0lgaWU8skgO7xupPTkyuwheSckejFLK5T4ZOo0Gda9viaIhpD1Qn7JqqlKAJqC'
1750
        'QplPKp2nqBWAfwBGaOwVrz3y1T+UZZNismXHsb2Jq18T+VaD9k4P8DqE3g70qV'
1751
        'JLurpnDI6VS5oqDDPVbtVjMxMxMg4rzQVipn2Bv1fVNK0iq3Gl0hhnnHKm/egy'
1752
        'nWQ7QH/F3JFOFCQ0aSPfA='
1753
        ).decode('base64')
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1754
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1755
    def test_repository_tarball(self):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1756
        # Test that Repository.tarball generates the right operations
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1757
        transport_path = 'repo'
2018.18.14 by Martin Pool
merge hpss again; restore incorrectly removed RemoteRepository.break_lock
1758
        expected_calls = [('call_expecting_body', 'Repository.tarball',
3104.4.2 by Andrew Bennetts
All tests passing.
1759
                           ('repo/', 'bz2',),),
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1760
            ]
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1761
        repo, client = self.setup_fake_client_and_repository(transport_path)
1762
        client.add_success_response_with_body(self.tarball_content, 'ok')
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1763
        # Now actually ask for the tarball
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1764
        tarball_file = repo._get_tarball('bz2')
2018.18.25 by Martin Pool
Repository.tarball fixes for python2.4
1765
        try:
1766
            self.assertEqual(expected_calls, client._calls)
1767
            self.assertEqual(self.tarball_content, tarball_file.read())
1768
        finally:
1769
            tarball_file.close()
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1770
1771
1772
class TestRemoteRepositoryCopyContent(tests.TestCaseWithTransport):
1773
    """RemoteRepository.copy_content_into optimizations"""
1774
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
1775
    def test_copy_content_remote_to_local(self):
1776
        self.transport_server = server.SmartTCPServer_for_testing
1777
        src_repo = self.make_repository('repo1')
1778
        src_repo = repository.Repository.open(self.get_url('repo1'))
1779
        # At the moment the tarball-based copy_content_into can't write back
1780
        # into a smart server.  It would be good if it could upload the
1781
        # tarball; once that works we'd have to create repositories of
1782
        # different formats. -- mbp 20070410
1783
        dest_url = self.get_vfs_only_url('repo2')
1784
        dest_bzrdir = BzrDir.create(dest_url)
1785
        dest_repo = dest_bzrdir.create_repository()
1786
        self.assertFalse(isinstance(dest_repo, RemoteRepository))
1787
        self.assertTrue(isinstance(src_repo, RemoteRepository))
1788
        src_repo.copy_content_into(dest_repo)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1789
1790
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1791
class _StubRealPackRepository(object):
1792
1793
    def __init__(self, calls):
1794
        self._pack_collection = _StubPackCollection(calls)
1795
1796
1797
class _StubPackCollection(object):
1798
1799
    def __init__(self, calls):
1800
        self.calls = calls
1801
1802
    def autopack(self):
1803
        self.calls.append(('pack collection autopack',))
1804
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
1805
    def reload_pack_names(self):
1806
        self.calls.append(('pack collection reload_pack_names',))
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1807
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1808
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1809
class TestRemotePackRepositoryAutoPack(TestRemoteRepository):
1810
    """Tests for RemoteRepository.autopack implementation."""
1811
1812
    def test_ok(self):
1813
        """When the server returns 'ok' and there's no _real_repository, then
1814
        nothing else happens: the autopack method is done.
1815
        """
1816
        transport_path = 'quack'
1817
        repo, client = self.setup_fake_client_and_repository(transport_path)
1818
        client.add_expected_call(
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
1819
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1820
        repo.autopack()
1821
        client.finished_test()
1822
1823
    def test_ok_with_real_repo(self):
1824
        """When the server returns 'ok' and there is a _real_repository, then
1825
        the _real_repository's reload_pack_name's method will be called.
1826
        """
1827
        transport_path = 'quack'
1828
        repo, client = self.setup_fake_client_and_repository(transport_path)
1829
        client.add_expected_call(
1830
            'PackRepository.autopack', ('quack/',),
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
1831
            'success', ('ok',))
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1832
        repo._real_repository = _StubRealPackRepository(client._calls)
1833
        repo.autopack()
1834
        self.assertEqual(
1835
            [('call', 'PackRepository.autopack', ('quack/',)),
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
1836
             ('pack collection reload_pack_names',)],
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1837
            client._calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1838
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1839
    def test_backwards_compatibility(self):
1840
        """If the server does not recognise the PackRepository.autopack verb,
1841
        fallback to the real_repository's implementation.
1842
        """
1843
        transport_path = 'quack'
1844
        repo, client = self.setup_fake_client_and_repository(transport_path)
1845
        client.add_unknown_method_response('PackRepository.autopack')
1846
        def stub_ensure_real():
1847
            client._calls.append(('_ensure_real',))
1848
            repo._real_repository = _StubRealPackRepository(client._calls)
1849
        repo._ensure_real = stub_ensure_real
1850
        repo.autopack()
1851
        self.assertEqual(
1852
            [('call', 'PackRepository.autopack', ('quack/',)),
1853
             ('_ensure_real',),
1854
             ('pack collection autopack',)],
1855
            client._calls)
1856
1857
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1858
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
1859
    """Base class for unit tests for bzrlib.remote._translate_error."""
1860
1861
    def translateTuple(self, error_tuple, **context):
1862
        """Call _translate_error with an ErrorFromSmartServer built from the
1863
        given error_tuple.
1864
1865
        :param error_tuple: A tuple of a smart server response, as would be
1866
            passed to an ErrorFromSmartServer.
1867
        :kwargs context: context items to call _translate_error with.
1868
1869
        :returns: The error raised by _translate_error.
1870
        """
1871
        # Raise the ErrorFromSmartServer before passing it as an argument,
1872
        # because _translate_error may need to re-raise it with a bare 'raise'
1873
        # statement.
1874
        server_error = errors.ErrorFromSmartServer(error_tuple)
1875
        translated_error = self.translateErrorFromSmartServer(
1876
            server_error, **context)
1877
        return translated_error
1878
1879
    def translateErrorFromSmartServer(self, error_object, **context):
1880
        """Like translateTuple, but takes an already constructed
1881
        ErrorFromSmartServer rather than a tuple.
1882
        """
1883
        try:
1884
            raise error_object
1885
        except errors.ErrorFromSmartServer, server_error:
1886
            translated_error = self.assertRaises(
1887
                errors.BzrError, remote._translate_error, server_error,
1888
                **context)
1889
        return translated_error
1890
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
1891
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1892
class TestErrorTranslationSuccess(TestErrorTranslationBase):
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1893
    """Unit tests for bzrlib.remote._translate_error.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1894
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1895
    Given an ErrorFromSmartServer (which has an error tuple from a smart
1896
    server) and some context, _translate_error raises more specific errors from
1897
    bzrlib.errors.
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1898
1899
    This test case covers the cases where _translate_error succeeds in
1900
    translating an ErrorFromSmartServer to something better.  See
1901
    TestErrorTranslationRobustness for other cases.
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1902
    """
1903
1904
    def test_NoSuchRevision(self):
1905
        branch = self.make_branch('')
1906
        revid = 'revid'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1907
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1908
            ('NoSuchRevision', revid), branch=branch)
1909
        expected_error = errors.NoSuchRevision(branch, revid)
1910
        self.assertEqual(expected_error, translated_error)
1911
1912
    def test_nosuchrevision(self):
1913
        repository = self.make_repository('')
1914
        revid = 'revid'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1915
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1916
            ('nosuchrevision', revid), repository=repository)
1917
        expected_error = errors.NoSuchRevision(repository, revid)
1918
        self.assertEqual(expected_error, translated_error)
1919
1920
    def test_nobranch(self):
1921
        bzrdir = self.make_bzrdir('')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1922
        translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1923
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
1924
        self.assertEqual(expected_error, translated_error)
1925
1926
    def test_LockContention(self):
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1927
        translated_error = self.translateTuple(('LockContention',))
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1928
        expected_error = errors.LockContention('(remote lock)')
1929
        self.assertEqual(expected_error, translated_error)
1930
1931
    def test_UnlockableTransport(self):
1932
        bzrdir = self.make_bzrdir('')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1933
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1934
            ('UnlockableTransport',), bzrdir=bzrdir)
1935
        expected_error = errors.UnlockableTransport(bzrdir.root_transport)
1936
        self.assertEqual(expected_error, translated_error)
1937
1938
    def test_LockFailed(self):
1939
        lock = 'str() of a server lock'
1940
        why = 'str() of why'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1941
        translated_error = self.translateTuple(('LockFailed', lock, why))
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1942
        expected_error = errors.LockFailed(lock, why)
1943
        self.assertEqual(expected_error, translated_error)
1944
1945
    def test_TokenMismatch(self):
1946
        token = 'a lock token'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1947
        translated_error = self.translateTuple(('TokenMismatch',), token=token)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1948
        expected_error = errors.TokenMismatch(token, '(remote token)')
1949
        self.assertEqual(expected_error, translated_error)
1950
1951
    def test_Diverged(self):
1952
        branch = self.make_branch('a')
1953
        other_branch = self.make_branch('b')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
1954
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
1955
            ('Diverged',), branch=branch, other_branch=other_branch)
1956
        expected_error = errors.DivergedBranches(branch, other_branch)
1957
        self.assertEqual(expected_error, translated_error)
1958
3786.4.2 by Andrew Bennetts
Add tests and fix code to make sure ReadError and PermissionDenied are robustly handled by _translate_error.
1959
    def test_ReadError_no_args(self):
1960
        path = 'a path'
1961
        translated_error = self.translateTuple(('ReadError',), path=path)
1962
        expected_error = errors.ReadError(path)
1963
        self.assertEqual(expected_error, translated_error)
1964
1965
    def test_ReadError(self):
1966
        path = 'a path'
1967
        translated_error = self.translateTuple(('ReadError', path))
1968
        expected_error = errors.ReadError(path)
1969
        self.assertEqual(expected_error, translated_error)
1970
1971
    def test_PermissionDenied_no_args(self):
1972
        path = 'a path'
1973
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
1974
        expected_error = errors.PermissionDenied(path)
1975
        self.assertEqual(expected_error, translated_error)
1976
1977
    def test_PermissionDenied_one_arg(self):
1978
        path = 'a path'
1979
        translated_error = self.translateTuple(('PermissionDenied', path))
1980
        expected_error = errors.PermissionDenied(path)
1981
        self.assertEqual(expected_error, translated_error)
1982
1983
    def test_PermissionDenied_one_arg_and_context(self):
1984
        """Given a choice between a path from the local context and a path on
1985
        the wire, _translate_error prefers the path from the local context.
1986
        """
1987
        local_path = 'local path'
1988
        remote_path = 'remote path'
1989
        translated_error = self.translateTuple(
1990
            ('PermissionDenied', remote_path), path=local_path)
1991
        expected_error = errors.PermissionDenied(local_path)
1992
        self.assertEqual(expected_error, translated_error)
1993
1994
    def test_PermissionDenied_two_args(self):
1995
        path = 'a path'
1996
        extra = 'a string with extra info'
1997
        translated_error = self.translateTuple(
1998
            ('PermissionDenied', path, extra))
1999
        expected_error = errors.PermissionDenied(path, extra)
2000
        self.assertEqual(expected_error, translated_error)
2001
2002
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2003
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2004
    """Unit tests for bzrlib.remote._translate_error's robustness.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2005
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2006
    TestErrorTranslationSuccess is for cases where _translate_error can
2007
    translate successfully.  This class about how _translate_err behaves when
2008
    it fails to translate: it re-raises the original error.
2009
    """
2010
2011
    def test_unrecognised_server_error(self):
2012
        """If the error code from the server is not recognised, the original
2013
        ErrorFromSmartServer is propagated unmodified.
2014
        """
2015
        error_tuple = ('An unknown error tuple',)
3690.1.2 by Andrew Bennetts
Rename UntranslateableErrorFromSmartServer -> UnknownErrorFromSmartServer.
2016
        server_error = errors.ErrorFromSmartServer(error_tuple)
2017
        translated_error = self.translateErrorFromSmartServer(server_error)
2018
        expected_error = errors.UnknownErrorFromSmartServer(server_error)
3690.1.1 by Andrew Bennetts
Unexpected error responses from a smart server no longer cause the client to traceback.
2019
        self.assertEqual(expected_error, translated_error)
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2020
2021
    def test_context_missing_a_key(self):
2022
        """In case of a bug in the client, or perhaps an unexpected response
2023
        from a server, _translate_error returns the original error tuple from
2024
        the server and mutters a warning.
2025
        """
2026
        # To translate a NoSuchRevision error _translate_error needs a 'branch'
2027
        # in the context dict.  So let's give it an empty context dict instead
2028
        # to exercise its error recovery.
2029
        empty_context = {}
2030
        error_tuple = ('NoSuchRevision', 'revid')
2031
        server_error = errors.ErrorFromSmartServer(error_tuple)
2032
        translated_error = self.translateErrorFromSmartServer(server_error)
2033
        self.assertEqual(server_error, translated_error)
2034
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2035
        # been muttered to the log file for developer to look at.
2036
        self.assertContainsRe(
2037
            self._get_log(keep_log_file=True),
2038
            "Missing key 'branch' in context")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2039
3786.4.2 by Andrew Bennetts
Add tests and fix code to make sure ReadError and PermissionDenied are robustly handled by _translate_error.
2040
    def test_path_missing(self):
2041
        """Some translations (PermissionDenied, ReadError) can determine the
2042
        'path' variable from either the wire or the local context.  If neither
2043
        has it, then an error is raised.
2044
        """
2045
        error_tuple = ('ReadError',)
2046
        server_error = errors.ErrorFromSmartServer(error_tuple)
2047
        translated_error = self.translateErrorFromSmartServer(server_error)
2048
        self.assertEqual(server_error, translated_error)
2049
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2050
        # been muttered to the log file for developer to look at.
2051
        self.assertContainsRe(
2052
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
2053
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2054
2055
class TestStacking(tests.TestCaseWithTransport):
2056
    """Tests for operations on stacked remote repositories.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2057
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2058
    The underlying format type must support stacking.
2059
    """
2060
2061
    def test_access_stacked_remote(self):
2062
        # based on <http://launchpad.net/bugs/261315>
2063
        # make a branch stacked on another repository containing an empty
2064
        # revision, then open it over hpss - we should be able to see that
2065
        # revision.
2066
        base_transport = self.get_transport()
2067
        base_builder = self.make_branch_builder('base', format='1.6')
2068
        base_builder.start_series()
2069
        base_revid = base_builder.build_snapshot('rev-id', None,
2070
            [('add', ('', None, 'directory', None))],
2071
            'message')
2072
        base_builder.finish_series()
2073
        stacked_branch = self.make_branch('stacked', format='1.6')
2074
        stacked_branch.set_stacked_on_url('../base')
2075
        # start a server looking at this
2076
        smart_server = server.SmartTCPServer_for_testing()
2077
        smart_server.setUp()
2078
        self.addCleanup(smart_server.tearDown)
2079
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2080
        # can get its branch and repository
2081
        remote_branch = remote_bzrdir.open_branch()
2082
        remote_repo = remote_branch.repository
3691.2.6 by Martin Pool
Disable RemoteBranch stacking, but get get_stacked_on_url working, and passing back exceptions
2083
        remote_repo.lock_read()
2084
        try:
2085
            # it should have an appropriate fallback repository, which should also
2086
            # be a RemoteRepository
2087
            self.assertEquals(len(remote_repo._fallback_repositories), 1)
2088
            self.assertIsInstance(remote_repo._fallback_repositories[0],
2089
                RemoteRepository)
2090
            # and it has the revision committed to the underlying repository;
2091
            # these have varying implementations so we try several of them
2092
            self.assertTrue(remote_repo.has_revisions([base_revid]))
2093
            self.assertTrue(remote_repo.has_revision(base_revid))
2094
            self.assertEqual(remote_repo.get_revision(base_revid).message,
2095
                'message')
2096
        finally:
2097
            remote_repo.unlock()
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2098
3835.1.7 by Aaron Bentley
Updates from review
2099
    def prepare_stacked_remote_branch(self):
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2100
        smart_server = server.SmartTCPServer_for_testing()
2101
        smart_server.setUp()
2102
        self.addCleanup(smart_server.tearDown)
2103
        tree1 = self.make_branch_and_tree('tree1')
2104
        tree1.commit('rev1', rev_id='rev1')
2105
        tree2 = self.make_branch_and_tree('tree2', format='1.6')
2106
        tree2.branch.set_stacked_on_url(tree1.branch.base)
2107
        branch2 = Branch.open(smart_server.get_url() + '/tree2')
2108
        branch2.lock_read()
2109
        self.addCleanup(branch2.unlock)
3835.1.7 by Aaron Bentley
Updates from review
2110
        return branch2
2111
2112
    def test_stacked_get_parent_map(self):
2113
        # the public implementation of get_parent_map obeys stacking
2114
        branch = self.prepare_stacked_remote_branch()
2115
        repo = branch.repository
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2116
        self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
3835.1.7 by Aaron Bentley
Updates from review
2117
3835.1.10 by Aaron Bentley
Move CachingExtraParentsProvider to Graph
2118
    def test_unstacked_get_parent_map(self):
2119
        # _unstacked_provider.get_parent_map ignores stacking
3835.1.7 by Aaron Bentley
Updates from review
2120
        branch = self.prepare_stacked_remote_branch()
3835.1.10 by Aaron Bentley
Move CachingExtraParentsProvider to Graph
2121
        provider = branch.repository._unstacked_provider
3835.1.8 by Aaron Bentley
Make UnstackedParentsProvider manage the cache
2122
        self.assertEqual([], provider.get_parent_map(['rev1']).keys())
3834.3.3 by John Arbash Meinel
Merge bzr.dev, resolve conflict in tests.
2123
3834.3.2 by Andrew Bennetts
Preserve BzrBranch5's _synchronize_history code without affecting Branch or BzrBranch7; add effort test for RemoteBranch.copy_content_into.
2124
2125
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
2126
2127
    def setUp(self):
2128
        super(TestRemoteBranchEffort, self).setUp()
2129
        # Create a smart server that publishes whatever the backing VFS server
2130
        # does.
2131
        self.smart_server = server.SmartTCPServer_for_testing()
2132
        self.smart_server.setUp(self.get_server())
2133
        self.addCleanup(self.smart_server.tearDown)
2134
        # Log all HPSS calls into self.hpss_calls.
2135
        _SmartClient.hooks.install_named_hook(
2136
            'call', self.capture_hpss_call, None)
2137
        self.hpss_calls = []
2138
2139
    def capture_hpss_call(self, params):
2140
        self.hpss_calls.append(params.method)
2141
2142
    def test_copy_content_into_avoids_revision_history(self):
2143
        local = self.make_branch('local')
2144
        remote_backing_tree = self.make_branch_and_tree('remote')
2145
        remote_backing_tree.commit("Commit.")
2146
        remote_branch_url = self.smart_server.get_url() + 'remote'
2147
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
2148
        local.repository.fetch(remote_branch.repository)
2149
        self.hpss_calls = []
2150
        remote_branch.copy_content_into(local)
3834.3.3 by John Arbash Meinel
Merge bzr.dev, resolve conflict in tests.
2151
        self.assertFalse('Branch.revision_history' in self.hpss_calls)