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