/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1
# Copyright (C) 2006, 2007, 2008, 2009 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
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,
4476.3.36 by Andrew Bennetts
Add a somewhat complex test to exercise the fallback-to-vfs logic in RemoteSink when an inventory-delta is encountered and the 1.18 verb isn't accepted.
34
    inventory,
2535.3.39 by Andrew Bennetts
Tidy some XXXs.
35
    pack,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
36
    remote,
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
37
    repository,
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
38
    smart,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
39
    tests,
4190.1.4 by Robert Collins
Cache ghosts when we can get them from a RemoteRepository in get_parent_map.
40
    treebuilder,
3691.2.4 by Martin Pool
Add FakeRemoteTransport to clarify test_remote
41
    urlutils,
4476.3.36 by Andrew Bennetts
Add a somewhat complex test to exercise the fallback-to-vfs logic in RemoteSink when an inventory-delta is encountered and the 1.18 verb isn't accepted.
42
    versionedfile,
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
43
    )
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
44
from bzrlib.branch import Branch
45
from bzrlib.bzrdir import BzrDir, BzrDirFormat
46
from bzrlib.remote import (
47
    RemoteBranch,
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
48
    RemoteBranchFormat,
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
49
    RemoteBzrDir,
50
    RemoteBzrDirFormat,
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
51
    RemoteRepository,
4183.5.1 by Robert Collins
Add RepositoryFormat.fast_deltas to signal fast delta creation.
52
    RemoteRepositoryFormat,
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
53
    )
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
54
from bzrlib.repofmt import groupcompress_repo, pack_repo
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
55
from bzrlib.revision import NULL_REVISION
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
56
from bzrlib.smart import server, medium
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
57
from bzrlib.smart.client import _SmartClient
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
58
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
59
from bzrlib.tests import (
60
    condition_isinstance,
61
    split_suite_by_condition,
62
    multiply_tests,
4301.3.1 by Andrew Bennetts
Implement RemoteBranch.set_append_revisions_only.
63
    KnownFailure,
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
64
    )
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
65
from bzrlib.transport import get_transport, http
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
66
from bzrlib.transport.memory import MemoryTransport
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
67
from bzrlib.transport.remote import (
68
    RemoteTransport,
69
    RemoteSSHTransport,
70
    RemoteTCPTransport,
71
)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
72
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
73
def load_tests(standard_tests, module, loader):
74
    to_adapt, result = split_suite_by_condition(
75
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
76
    smart_server_version_scenarios = [
4104.4.2 by Robert Collins
Fix test_source for 1.13 landing.
77
        ('HPSS-v2',
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
78
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
4104.4.2 by Robert Collins
Fix test_source for 1.13 landing.
79
        ('HPSS-v3',
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
80
            {'transport_server': server.SmartTCPServer_for_testing})]
81
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
82
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)
83
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
84
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
85
86
    def setUp(self):
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
87
        super(BasicRemoteObjectTests, self).setUp()
88
        self.transport = self.get_transport()
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
89
        # 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
90
        self.local_wt = BzrDir.create_standalone_workingtree('.')
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
91
2018.5.171 by Andrew Bennetts
Disconnect RemoteTransports in some tests to avoid tripping up test_strace with leftover threads from previous tests.
92
    def tearDown(self):
93
        self.transport.disconnect()
94
        tests.TestCaseWithTransport.tearDown(self)
95
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
96
    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.
97
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
98
        self.assertIsInstance(b, BzrDir)
99
100
    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.
101
        # 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.
102
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
103
        branch = b.open_branch()
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
104
        self.assertIsInstance(branch, Branch)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
105
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
106
    def test_remote_repository(self):
107
        b = BzrDir.open_from_transport(self.transport)
108
        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.
109
        revid = u'\xc823123123'.encode('utf8')
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
110
        self.assertFalse(repo.has_revision(revid))
111
        self.local_wt.commit(message='test commit', rev_id=revid)
112
        self.assertTrue(repo.has_revision(revid))
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
113
114
    def test_remote_branch_revision_history(self):
115
        b = BzrDir.open_from_transport(self.transport).open_branch()
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
116
        self.assertEqual([], b.revision_history())
117
        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.
118
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
119
        self.assertEqual([r1, r2], b.revision_history())
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
120
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
121
    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)
122
        """Should open a RemoteBzrDir over a RemoteTransport"""
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
123
        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.
124
        self.assertTrue(RemoteBzrDirFormat
125
                        in BzrDirFormat._control_server_formats)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
126
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
127
128
    def test_open_detected_smart_format(self):
129
        fmt = BzrDirFormat.find_format(self.transport)
130
        d = fmt.open(self.transport)
131
        self.assertIsInstance(d, BzrDir)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
132
2477.1.1 by Martin Pool
Add RemoteBranch repr
133
    def test_remote_branch_repr(self):
134
        b = BzrDir.open_from_transport(self.transport).open_branch()
135
        self.assertStartsWith(str(b), 'RemoteBranch(')
136
4103.2.2 by Andrew Bennetts
Fix RemoteBranchFormat.supports_stacking()
137
    def test_remote_branch_format_supports_stacking(self):
138
        t = self.transport
139
        self.make_branch('unstackable', format='pack-0.92')
140
        b = BzrDir.open_from_transport(t.clone('unstackable')).open_branch()
141
        self.assertFalse(b._format.supports_stacking())
142
        self.make_branch('stackable', format='1.9')
143
        b = BzrDir.open_from_transport(t.clone('stackable')).open_branch()
144
        self.assertTrue(b._format.supports_stacking())
145
4118.1.1 by Andrew Bennetts
Fix performance regression (many small round-trips) when pushing to a remote pack, and tidy the tests.
146
    def test_remote_repo_format_supports_external_references(self):
147
        t = self.transport
148
        bd = self.make_bzrdir('unstackable', format='pack-0.92')
149
        r = bd.create_repository()
150
        self.assertFalse(r._format.supports_external_lookups)
151
        r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
152
        self.assertFalse(r._format.supports_external_lookups)
153
        bd = self.make_bzrdir('stackable', format='1.9')
154
        r = bd.create_repository()
155
        self.assertTrue(r._format.supports_external_lookups)
156
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
157
        self.assertTrue(r._format.supports_external_lookups)
158
4301.3.1 by Andrew Bennetts
Implement RemoteBranch.set_append_revisions_only.
159
    def test_remote_branch_set_append_revisions_only(self):
160
        # Make a format 1.9 branch, which supports append_revisions_only
161
        branch = self.make_branch('branch', format='1.9')
162
        config = branch.get_config()
163
        branch.set_append_revisions_only(True)
164
        self.assertEqual(
165
            'True', config.get_user_option('append_revisions_only'))
166
        branch.set_append_revisions_only(False)
167
        self.assertEqual(
168
            'False', config.get_user_option('append_revisions_only'))
169
170
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
171
        branch = self.make_branch('branch', format='knit')
172
        config = branch.get_config()
173
        self.assertRaises(
4301.3.3 by Andrew Bennetts
Move check onto base Branch class, and add a supports_set_append_revisions_only method to BranchFormat, as suggested by Robert.
174
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
4301.3.1 by Andrew Bennetts
Implement RemoteBranch.set_append_revisions_only.
175
3691.2.4 by Martin Pool
Add FakeRemoteTransport to clarify test_remote
176
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
177
class FakeProtocol(object):
178
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
179
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
180
    def __init__(self, body, fake_client):
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
181
        self.body = body
182
        self._body_buffer = None
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
183
        self._fake_client = fake_client
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
184
185
    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.
186
        if self._body_buffer is None:
187
            self._body_buffer = StringIO(self.body)
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
188
        bytes = self._body_buffer.read(count)
189
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
190
            self._fake_client.expecting_body = False
191
        return bytes
192
193
    def cancel_read_body(self):
194
        self._fake_client.expecting_body = False
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
195
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
196
    def read_streamed_body(self):
197
        return self.body
198
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
199
2018.5.159 by Andrew Bennetts
Rename SmartClient to _SmartClient.
200
class FakeClient(_SmartClient):
201
    """Lookalike for _SmartClient allowing testing."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
202
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
203
    def __init__(self, fake_medium_base='fake base'):
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
204
        """Create a FakeClient."""
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
205
        self.responses = []
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
206
        self._calls = []
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
207
        self.expecting_body = False
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
208
        # if non-None, this is the list of expected calls, with only the
209
        # 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.
210
        # compute so is not included. If a call is None, that call can
211
        # be anything.
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
212
        self._expected_calls = None
3431.3.2 by Andrew Bennetts
Remove 'base' from _SmartClient entirely, now that the medium has it.
213
        _SmartClient.__init__(self, FakeMedium(self._calls, fake_medium_base))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
214
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
215
    def add_expected_call(self, call_name, call_args, response_type,
216
        response_args, response_body=None):
217
        if self._expected_calls is None:
218
            self._expected_calls = []
219
        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
220
        self.responses.append((response_type, response_args, response_body))
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
221
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
222
    def add_success_response(self, *args):
223
        self.responses.append(('success', args, None))
224
225
    def add_success_response_with_body(self, body, *args):
226
        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.
227
        if self._expected_calls is not None:
228
            self._expected_calls.append(None)
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
229
230
    def add_error_response(self, *args):
231
        self.responses.append(('error', args))
232
233
    def add_unknown_method_response(self, verb):
234
        self.responses.append(('unknown', verb))
235
3691.2.8 by Martin Pool
Update some test_remote tests for Branch.get_stacked_on_url and with clearer assertions
236
    def finished_test(self):
237
        if self._expected_calls:
238
            raise AssertionError("%r finished but was still expecting %r"
239
                % (self, self._expected_calls[0]))
240
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.
241
    def _get_next_response(self):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
242
        try:
243
            response_tuple = self.responses.pop(0)
244
        except IndexError, e:
245
            raise AssertionError("%r didn't expect any more calls"
246
                % (self,))
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
247
        if response_tuple[0] == 'unknown':
248
            raise errors.UnknownSmartMethod(response_tuple[1])
249
        elif response_tuple[0] == 'error':
250
            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.
251
        return response_tuple
252
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
253
    def _check_call(self, method, args):
254
        if self._expected_calls is None:
255
            # the test should be updated to say what it expects
256
            return
257
        try:
258
            next_call = self._expected_calls.pop(0)
259
        except IndexError:
260
            raise AssertionError("%r didn't expect any more calls "
261
                "but got %r%r"
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
262
                % (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.
263
        if next_call is None:
264
            return
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
265
        if method != next_call[0] or args != next_call[1]:
266
            raise AssertionError("%r expected %r%r "
267
                "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
268
                % (self, next_call[0], next_call[1], method, args,))
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
269
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
270
    def call(self, method, *args):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
271
        self._check_call(method, args)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
272
        self._calls.append(('call', method, args))
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
273
        return self._get_next_response()[1]
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
274
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
275
    def call_expecting_body(self, method, *args):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
276
        self._check_call(method, args)
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
277
        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.
278
        result = self._get_next_response()
2535.3.68 by Andrew Bennetts
Backwards compatibility for new smart method.
279
        self.expecting_body = True
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
280
        return result[1], FakeProtocol(result[2], self)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
281
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.
282
    def call_with_body_bytes_expecting_body(self, method, args, body):
3691.2.7 by Martin Pool
FakeClient can know what calls to expect
283
        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.
284
        self._calls.append(('call_with_body_bytes_expecting_body', method,
285
            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.
286
        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.
287
        self.expecting_body = True
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
288
        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.
289
3842.3.9 by Andrew Bennetts
Backing up the stream so that we can fallback correctly.
290
    def call_with_body_stream(self, args, stream):
291
        # Explicitly consume the stream before checking for an error, because
292
        # that's what happens a real medium.
293
        stream = list(stream)
294
        self._check_call(args[0], args[1:])
295
        self._calls.append(('call_with_body_stream', args[0], args[1:], stream))
4144.3.2 by Andrew Bennetts
Use Repository.insert_stream_locked if there is a lock_token for the remote repo.
296
        result = self._get_next_response()
4144.3.3 by Andrew Bennetts
Tweaks based on review from Robert.
297
        # The second value returned from call_with_body_stream is supposed to
298
        # be a response_handler object, but so far no tests depend on that.
299
        response_handler = None 
300
        return result[1], response_handler
3842.3.9 by Andrew Bennetts
Backing up the stream so that we can fallback correctly.
301
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
302
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
303
class FakeMedium(medium.SmartClientMedium):
3104.4.2 by Andrew Bennetts
All tests passing.
304
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.
305
    def __init__(self, client_calls, base):
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
306
        medium.SmartClientMedium.__init__(self, base)
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
307
        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.
308
309
    def disconnect(self):
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
310
        self._client_calls.append(('disconnect medium',))
3104.4.2 by Andrew Bennetts
All tests passing.
311
312
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.
313
class TestVfsHas(tests.TestCase):
314
315
    def test_unicode_path(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
316
        client = FakeClient('/')
317
        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.
318
        transport = RemoteTransport('bzr://localhost/', _client=client)
319
        filename = u'/hell\u00d8'.encode('utf8')
320
        result = transport.has(filename)
321
        self.assertEqual(
322
            [('call', 'has', (filename,))],
323
            client._calls)
324
        self.assertTrue(result)
325
326
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
327
class TestRemote(tests.TestCaseWithMemoryTransport):
4032.1.1 by John Arbash Meinel
Merge the removal of all trailing whitespace, and resolve conflicts.
328
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
329
    def get_branch_format(self):
330
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
331
        return reference_bzrdir_format.get_branch_format()
332
4053.1.2 by Robert Collins
Actually make this branch work.
333
    def get_repo_format(self):
334
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
335
        return reference_bzrdir_format.repository_format
336
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
337
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
338
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
339
    """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.
340
341
    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.
342
        """Assert that the result of
343
        SmartClientMedium.remote_path_from_transport is the expected value for
344
        a given client_base and transport_base.
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
345
        """
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
346
        client_medium = medium.SmartClientMedium(client_base)
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
347
        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.
348
        result = client_medium.remote_path_from_transport(transport)
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
349
        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.
350
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
351
    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.
352
        """SmartClientMedium.remote_path_from_transport calculates a URL for
353
        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.
354
        """
355
        self.assertRemotePath('xyz/', 'bzr://host/path', 'bzr://host/xyz')
356
        self.assertRemotePath(
357
            'path/xyz/', 'bzr://host/path', 'bzr://host/path/xyz')
358
3431.3.11 by Andrew Bennetts
Push remote_path_from_transport logic into SmartClientMedium, removing special-casing of bzr+http from _SmartClient.
359
    def assertRemotePathHTTP(self, expected, transport_base, relpath):
360
        """Assert that the result of
361
        HttpTransportBase.remote_path_from_transport is the expected value for
362
        a given transport_base and relpath of that transport.  (Note that
363
        HttpTransportBase is a subclass of SmartClientMedium)
364
        """
365
        base_transport = get_transport(transport_base)
366
        client_medium = base_transport.get_smart_medium()
367
        cloned_transport = base_transport.clone(relpath)
368
        result = client_medium.remote_path_from_transport(cloned_transport)
369
        self.assertEqual(expected, result)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
370
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
371
    def test_remote_path_from_transport_http(self):
372
        """Remote paths for HTTP transports are calculated differently to other
373
        transports.  They are just relative to the client base, not the root
374
        directory of the host.
375
        """
376
        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.
377
            self.assertRemotePathHTTP(
378
                '../xyz/', scheme + '//host/path', '../xyz/')
379
            self.assertRemotePathHTTP(
380
                'xyz/', scheme + '//host/path', 'xyz/')
3313.3.3 by Andrew Bennetts
Add tests for _SmartClient.remote_path_for_transport.
381
382
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
383
class Test_ClientMedium_remote_is_at_least(tests.TestCase):
384
    """Tests for the behaviour of client_medium.remote_is_at_least."""
385
386
    def test_initially_unlimited(self):
387
        """A fresh medium assumes that the remote side supports all
388
        versions.
389
        """
390
        client_medium = medium.SmartClientMedium('dummy base')
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
391
        self.assertFalse(client_medium._is_remote_before((99, 99)))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
392
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
393
    def test__remember_remote_is_before(self):
394
        """Calling _remember_remote_is_before ratchets down the known remote
395
        version.
396
        """
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
397
        client_medium = medium.SmartClientMedium('dummy base')
398
        # Mark the remote side as being less than 1.6.  The remote side may
399
        # still be 1.5.
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
400
        client_medium._remember_remote_is_before((1, 6))
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
401
        self.assertTrue(client_medium._is_remote_before((1, 6)))
402
        self.assertFalse(client_medium._is_remote_before((1, 5)))
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
403
        # Calling _remember_remote_is_before again with a lower value works.
404
        client_medium._remember_remote_is_before((1, 5))
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
405
        self.assertTrue(client_medium._is_remote_before((1, 5)))
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
406
        # 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.
407
        self.assertRaises(
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
408
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
3453.4.1 by Andrew Bennetts
Better infrastructure on SmartClientMedium for tracking the remote version.
409
410
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
411
class TestBzrDirCloningMetaDir(TestRemote):
412
413
    def test_backwards_compat(self):
414
        self.setup_smart_server_with_call_log()
415
        a_dir = self.make_bzrdir('.')
416
        self.reset_smart_call_log()
417
        verb = 'BzrDir.cloning_metadir'
418
        self.disable_verb(verb)
419
        format = a_dir.cloning_metadir()
420
        call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
421
            call.call.method == verb])
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
422
        self.assertEqual(1, call_count)
423
4160.2.9 by Andrew Bennetts
Fix BzrDir.cloning_metadir RPC to fail on branch references, and make
424
    def test_branch_reference(self):
425
        transport = self.get_transport('quack')
426
        referenced = self.make_branch('referenced')
427
        expected = referenced.bzrdir.cloning_metadir()
428
        client = FakeClient(transport.base)
429
        client.add_expected_call(
430
            'BzrDir.cloning_metadir', ('quack/', 'False'),
431
            'error', ('BranchReference',)),
432
        client.add_expected_call(
433
            'BzrDir.open_branchV2', ('quack/',),
434
            'success', ('ref', self.get_url('referenced'))),
435
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
436
            _client=client)
437
        result = a_bzrdir.cloning_metadir()
438
        # We should have got a control dir matching the referenced branch.
439
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
440
        self.assertEqual(expected._repository_format, result._repository_format)
441
        self.assertEqual(expected._branch_format, result._branch_format)
442
        client.finished_test()
443
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
444
    def test_current_server(self):
445
        transport = self.get_transport('.')
446
        transport = transport.clone('quack')
447
        self.make_bzrdir('quack')
448
        client = FakeClient(transport.base)
449
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
450
        control_name = reference_bzrdir_format.network_name()
451
        client.add_expected_call(
452
            'BzrDir.cloning_metadir', ('quack/', 'False'),
4084.2.2 by Robert Collins
Review feedback.
453
            'success', (control_name, '', ('branch', ''))),
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
454
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
455
            _client=client)
456
        result = a_bzrdir.cloning_metadir()
457
        # We should have got a reference control dir with default branch and
458
        # repository formats.
459
        # This pokes a little, just to be sure.
460
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
4070.2.8 by Robert Collins
Really test the current BzrDir.cloning_metadir contract.
461
        self.assertEqual(None, result._repository_format)
462
        self.assertEqual(None, result._branch_format)
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
463
        client.finished_test()
464
465
4053.1.2 by Robert Collins
Actually make this branch work.
466
class TestBzrDirOpenBranch(TestRemote):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
467
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
468
    def test_backwards_compat(self):
469
        self.setup_smart_server_with_call_log()
470
        self.make_branch('.')
471
        a_dir = BzrDir.open(self.get_url('.'))
472
        self.reset_smart_call_log()
473
        verb = 'BzrDir.open_branchV2'
474
        self.disable_verb(verb)
475
        format = a_dir.open_branch()
476
        call_count = len([call for call in self.hpss_calls if
477
            call.call.method == verb])
478
        self.assertEqual(1, call_count)
479
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
480
    def test_branch_present(self):
4053.1.2 by Robert Collins
Actually make this branch work.
481
        reference_format = self.get_repo_format()
482
        network_name = reference_format.network_name()
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
483
        branch_network_name = self.get_branch_format().network_name()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
484
        transport = MemoryTransport()
485
        transport.mkdir('quack')
486
        transport = transport.clone('quack')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
487
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
488
        client.add_expected_call(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
489
            'BzrDir.open_branchV2', ('quack/',),
490
            'success', ('branch', branch_network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
491
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
492
            'BzrDir.find_repositoryV3', ('quack/',),
493
            'success', ('ok', '', 'no', 'no', 'no', network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
494
        client.add_expected_call(
495
            'Branch.get_stacked_on_url', ('quack/',),
496
            '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.
497
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
498
            _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
499
        result = bzrdir.open_branch()
500
        self.assertIsInstance(result, RemoteBranch)
501
        self.assertEqual(bzrdir, result.bzrdir)
3691.2.10 by Martin Pool
Update more test_remote tests
502
        client.finished_test()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
503
504
    def test_branch_missing(self):
505
        transport = MemoryTransport()
506
        transport.mkdir('quack')
507
        transport = transport.clone('quack')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
508
        client = FakeClient(transport.base)
509
        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.
510
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
511
            _client=client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
512
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
513
        self.assertEqual(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
514
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
515
            client._calls)
516
3211.4.1 by Robert Collins
* ``RemoteBzrDir._get_tree_branch`` no longer triggers ``_ensure_real``,
517
    def test__get_tree_branch(self):
518
        # _get_tree_branch is a form of open_branch, but it should only ask for
519
        # branch opening, not any other network requests.
520
        calls = []
521
        def open_branch():
522
            calls.append("Called")
523
            return "a-branch"
524
        transport = MemoryTransport()
525
        # 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.
526
        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.
527
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
528
            _client=client)
3211.4.1 by Robert Collins
* ``RemoteBzrDir._get_tree_branch`` no longer triggers ``_ensure_real``,
529
        # patch the open_branch call to record that it was called.
530
        bzrdir.open_branch = open_branch
531
        self.assertEqual((None, "a-branch"), bzrdir._get_tree_branch())
532
        self.assertEqual(["Called"], calls)
533
        self.assertEqual([], client._calls)
534
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.
535
    def test_url_quoting_of_path(self):
536
        # Relpaths on the wire should not be URL-escaped.  So "~" should be
537
        # 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.
538
        transport = RemoteTCPTransport('bzr://localhost/~hello/')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
539
        client = FakeClient(transport.base)
4053.1.2 by Robert Collins
Actually make this branch work.
540
        reference_format = self.get_repo_format()
541
        network_name = reference_format.network_name()
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
542
        branch_network_name = self.get_branch_format().network_name()
3691.2.10 by Martin Pool
Update more test_remote tests
543
        client.add_expected_call(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
544
            'BzrDir.open_branchV2', ('~hello/',),
545
            'success', ('branch', branch_network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
546
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
547
            'BzrDir.find_repositoryV3', ('~hello/',),
548
            'success', ('ok', '', 'no', 'no', 'no', network_name))
3691.2.10 by Martin Pool
Update more test_remote tests
549
        client.add_expected_call(
550
            'Branch.get_stacked_on_url', ('~hello/',),
551
            '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.
552
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
553
            _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.
554
        result = bzrdir.open_branch()
3691.2.10 by Martin Pool
Update more test_remote tests
555
        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.
556
3221.3.3 by Robert Collins
* Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
557
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
4053.1.2 by Robert Collins
Actually make this branch work.
558
        reference_format = self.get_repo_format()
559
        network_name = reference_format.network_name()
3104.4.2 by Andrew Bennetts
All tests passing.
560
        transport = MemoryTransport()
561
        transport.mkdir('quack')
562
        transport = transport.clone('quack')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
563
        if rich_root:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
564
            rich_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
565
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
566
            rich_response = 'no'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
567
        if subtrees:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
568
            subtree_response = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
569
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
570
            subtree_response = 'no'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
571
        client = FakeClient(transport.base)
572
        client.add_success_response(
4053.1.2 by Robert Collins
Actually make this branch work.
573
            'ok', '', rich_response, subtree_response, external_lookup,
574
            network_name)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
575
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
576
            _client=client)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
577
        result = bzrdir.open_repository()
578
        self.assertEqual(
4053.1.2 by Robert Collins
Actually make this branch work.
579
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
580
            client._calls)
581
        self.assertIsInstance(result, RemoteRepository)
582
        self.assertEqual(bzrdir, result.bzrdir)
583
        self.assertEqual(rich_root, result._format.rich_root_data)
2018.5.138 by Robert Collins
Merge bzr.dev.
584
        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.
585
586
    def test_open_repository_sets_format_attributes(self):
587
        self.check_open_repository(True, True)
588
        self.check_open_repository(False, True)
589
        self.check_open_repository(True, False)
590
        self.check_open_repository(False, False)
3221.3.3 by Robert Collins
* Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
591
        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.
592
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
593
    def test_old_server(self):
594
        """RemoteBzrDirFormat should fail to probe if the server version is too
595
        old.
596
        """
597
        self.assertRaises(errors.NotBranchError,
598
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
599
600
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
601
class TestBzrDirCreateBranch(TestRemote):
602
603
    def test_backwards_compat(self):
604
        self.setup_smart_server_with_call_log()
605
        repo = self.make_repository('.')
606
        self.reset_smart_call_log()
607
        self.disable_verb('BzrDir.create_branch')
608
        branch = repo.bzrdir.create_branch()
609
        create_branch_call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
610
            call.call.method == 'BzrDir.create_branch'])
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
611
        self.assertEqual(1, create_branch_call_count)
612
613
    def test_current_server(self):
614
        transport = self.get_transport('.')
615
        transport = transport.clone('quack')
616
        self.make_repository('quack')
617
        client = FakeClient(transport.base)
618
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
619
        reference_format = reference_bzrdir_format.get_branch_format()
620
        network_name = reference_format.network_name()
621
        reference_repo_fmt = reference_bzrdir_format.repository_format
622
        reference_repo_name = reference_repo_fmt.network_name()
623
        client.add_expected_call(
624
            'BzrDir.create_branch', ('quack/', network_name),
625
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
626
            reference_repo_name))
627
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
628
            _client=client)
629
        branch = a_bzrdir.create_branch()
630
        # We should have got a remote branch
631
        self.assertIsInstance(branch, remote.RemoteBranch)
632
        # its format should have the settings from the response
633
        format = branch._format
634
        self.assertEqual(network_name, format.network_name())
635
636
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
637
class TestBzrDirCreateRepository(TestRemote):
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
638
639
    def test_backwards_compat(self):
640
        self.setup_smart_server_with_call_log()
641
        bzrdir = self.make_bzrdir('.')
642
        self.reset_smart_call_log()
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
643
        self.disable_verb('BzrDir.create_repository')
644
        repo = bzrdir.create_repository()
645
        create_repo_call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
646
            call.call.method == 'BzrDir.create_repository'])
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
647
        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.
648
649
    def test_current_server(self):
650
        transport = self.get_transport('.')
651
        transport = transport.clone('quack')
652
        self.make_bzrdir('quack')
653
        client = FakeClient(transport.base)
654
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
655
        reference_format = reference_bzrdir_format.repository_format
656
        network_name = reference_format.network_name()
657
        client.add_expected_call(
658
            'BzrDir.create_repository', ('quack/',
659
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
660
            'success', ('ok', 'no', 'no', 'no', network_name))
661
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
662
            _client=client)
663
        repo = a_bzrdir.create_repository()
664
        # We should have got a remote repository
665
        self.assertIsInstance(repo, remote.RemoteRepository)
666
        # its format should have the settings from the response
667
        format = repo._format
668
        self.assertFalse(format.rich_root_data)
669
        self.assertFalse(format.supports_tree_reference)
670
        self.assertFalse(format.supports_external_lookups)
671
        self.assertEqual(network_name, format.network_name())
672
673
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
674
class TestBzrDirOpenRepository(TestRemote):
675
676
    def test_backwards_compat_1_2_3(self):
677
        # fallback all the way to the first version.
678
        reference_format = self.get_repo_format()
679
        network_name = reference_format.network_name()
680
        client = FakeClient('bzr://example.com/')
681
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
682
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
683
        client.add_success_response('ok', '', 'no', 'no')
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
684
        # A real repository instance will be created to determine the network
685
        # name.
686
        client.add_success_response_with_body(
687
            "Bazaar-NG meta directory, format 1\n", 'ok')
688
        client.add_success_response_with_body(
689
            reference_format.get_format_string(), 'ok')
690
        # PackRepository wants to do a stat
691
        client.add_success_response('stat', '0', '65535')
692
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
693
            _client=client)
694
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
695
            _client=client)
696
        repo = bzrdir.open_repository()
697
        self.assertEqual(
698
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
699
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
700
             ('call', 'BzrDir.find_repository', ('quack/',)),
701
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
702
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
703
             ('call', 'stat', ('/quack/.bzr/repository',)),
704
             ],
705
            client._calls)
706
        self.assertEqual(network_name, repo._format.network_name())
707
708
    def test_backwards_compat_2(self):
709
        # fallback to find_repositoryV2
710
        reference_format = self.get_repo_format()
711
        network_name = reference_format.network_name()
712
        client = FakeClient('bzr://example.com/')
713
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
714
        client.add_success_response('ok', '', 'no', 'no', 'no')
715
        # A real repository instance will be created to determine the network
716
        # name.
717
        client.add_success_response_with_body(
718
            "Bazaar-NG meta directory, format 1\n", 'ok')
719
        client.add_success_response_with_body(
720
            reference_format.get_format_string(), 'ok')
721
        # PackRepository wants to do a stat
722
        client.add_success_response('stat', '0', '65535')
723
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
724
            _client=client)
725
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
726
            _client=client)
727
        repo = bzrdir.open_repository()
728
        self.assertEqual(
729
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
730
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
731
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
732
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
733
             ('call', 'stat', ('/quack/.bzr/repository',)),
734
             ],
735
            client._calls)
736
        self.assertEqual(network_name, repo._format.network_name())
737
738
    def test_current_server(self):
739
        reference_format = self.get_repo_format()
740
        network_name = reference_format.network_name()
741
        transport = MemoryTransport()
742
        transport.mkdir('quack')
743
        transport = transport.clone('quack')
744
        client = FakeClient(transport.base)
745
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
746
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
747
            _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.
748
        repo = bzrdir.open_repository()
749
        self.assertEqual(
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
750
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
751
            client._calls)
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
752
        self.assertEqual(network_name, repo._format.network_name())
3297.3.3 by Andrew Bennetts
SmartClientRequestProtocol*.read_response_tuple can now raise UnknownSmartMethod. Callers no longer need to do their own ad hoc unknown smart method error detection.
753
754
4384.1.1 by Andrew Bennetts
Translate ErrorFromSmartServer in RemoteBzrDirFormat.
755
class TestBzrDirFormatInitializeEx(TestRemote):
756
757
    def test_success(self):
758
        """Simple test for typical successful call."""
759
        fmt = bzrdir.RemoteBzrDirFormat()
760
        default_format_name = BzrDirFormat.get_default_format().network_name()
761
        transport = self.get_transport()
762
        client = FakeClient(transport.base)
763
        client.add_expected_call(
4436.1.1 by Andrew Bennetts
Rename BzrDirFormat.initialize_ex verb to BzrDirFormat.initialize_ex_1.16.
764
            'BzrDirFormat.initialize_ex_1.16',
4384.1.1 by Andrew Bennetts
Translate ErrorFromSmartServer in RemoteBzrDirFormat.
765
                (default_format_name, 'path', 'False', 'False', 'False', '',
766
                 '', '', '', 'False'),
767
            'success',
768
                ('.', 'no', 'no', 'yes', 'repo fmt', 'repo bzrdir fmt',
769
                 'bzrdir fmt', 'False', '', '', 'repo lock token'))
770
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
771
        # it's currently hard to test that without supplying a real remote
772
        # transport connected to a real server.
773
        result = fmt._initialize_on_transport_ex_rpc(client, 'path',
774
            transport, False, False, False, None, None, None, None, False)
775
        client.finished_test()
776
777
    def test_error(self):
778
        """Error responses are translated, e.g. 'PermissionDenied' raises the
779
        corresponding error from the client.
780
        """
781
        fmt = bzrdir.RemoteBzrDirFormat()
782
        default_format_name = BzrDirFormat.get_default_format().network_name()
783
        transport = self.get_transport()
784
        client = FakeClient(transport.base)
785
        client.add_expected_call(
4436.1.1 by Andrew Bennetts
Rename BzrDirFormat.initialize_ex verb to BzrDirFormat.initialize_ex_1.16.
786
            'BzrDirFormat.initialize_ex_1.16',
4384.1.1 by Andrew Bennetts
Translate ErrorFromSmartServer in RemoteBzrDirFormat.
787
                (default_format_name, 'path', 'False', 'False', 'False', '',
788
                 '', '', '', 'False'),
789
            'error',
790
                ('PermissionDenied', 'path', 'extra info'))
791
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
792
        # it's currently hard to test that without supplying a real remote
793
        # transport connected to a real server.
794
        err = self.assertRaises(errors.PermissionDenied,
795
            fmt._initialize_on_transport_ex_rpc, client, 'path', transport,
796
            False, False, False, None, None, None, None, False)
797
        self.assertEqual('path', err.path)
798
        self.assertEqual(': extra info', err.extra)
799
        client.finished_test()
800
4384.1.3 by Andrew Bennetts
Add test suggested by John.
801
    def test_error_from_real_server(self):
802
        """Integration test for error translation."""
803
        transport = self.make_smart_server('foo')
804
        transport = transport.clone('no-such-path')
805
        fmt = bzrdir.RemoteBzrDirFormat()
806
        err = self.assertRaises(errors.NoSuchFile,
807
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
808
4384.1.1 by Andrew Bennetts
Translate ErrorFromSmartServer in RemoteBzrDirFormat.
809
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
810
class OldSmartClient(object):
811
    """A fake smart client for test_old_version that just returns a version one
812
    response to the 'hello' (query version) command.
813
    """
814
815
    def get_request(self):
816
        input_file = StringIO('ok\x011\n')
817
        output_file = StringIO()
818
        client_medium = medium.SmartSimplePipesClientMedium(
819
            input_file, output_file)
820
        return medium.SmartClientStreamMediumRequest(client_medium)
821
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
822
    def protocol_version(self):
823
        return 1
824
2432.3.2 by Andrew Bennetts
Add test, and tidy implementation.
825
826
class OldServerTransport(object):
827
    """A fake transport for test_old_server that reports it's smart server
828
    protocol version as version one.
829
    """
830
831
    def __init__(self):
832
        self.base = 'fake:'
833
834
    def get_smart_client(self):
835
        return OldSmartClient()
836
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
837
4288.1.1 by Robert Collins
Add support for a RemoteBzrDirConfig to support optimising push operations which need to look for default stacking locations.
838
class RemoteBzrDirTestCase(TestRemote):
839
840
    def make_remote_bzrdir(self, transport, client):
841
        """Make a RemotebzrDir using 'client' as the _client."""
842
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
843
            _client=client)
844
845
846
class RemoteBranchTestCase(RemoteBzrDirTestCase):
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
847
848
    def make_remote_branch(self, transport, client):
849
        """Make a RemoteBranch using 'client' as its _SmartClient.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
850
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
851
        A RemoteBzrDir and RemoteRepository will also be created to fill out
852
        the RemoteBranch, albeit with stub values for some of their attributes.
853
        """
854
        # we do not want bzrdir to make any remote calls, so use False as its
855
        # _client.  If it tries to make a remote call, this will fail
856
        # immediately.
4288.1.1 by Robert Collins
Add support for a RemoteBzrDirConfig to support optimising push operations which need to look for default stacking locations.
857
        bzrdir = self.make_remote_bzrdir(transport, False)
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
858
        repo = RemoteRepository(bzrdir, None, _client=client)
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
859
        branch_format = self.get_branch_format()
860
        format = RemoteBranchFormat(network_name=branch_format.network_name())
861
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
862
863
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
864
class TestBranchGetParent(RemoteBranchTestCase):
865
866
    def test_no_parent(self):
867
        # in an empty branch we decode the response properly
868
        transport = MemoryTransport()
869
        client = FakeClient(transport.base)
870
        client.add_expected_call(
871
            'Branch.get_stacked_on_url', ('quack/',),
872
            'error', ('NotStacked',))
873
        client.add_expected_call(
874
            'Branch.get_parent', ('quack/',),
4083.1.7 by Andrew Bennetts
Fix same trivial bug [(x) != (x,)] in test_remote and test_smart.
875
            'success', ('',))
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
876
        transport.mkdir('quack')
877
        transport = transport.clone('quack')
878
        branch = self.make_remote_branch(transport, client)
879
        result = branch.get_parent()
880
        client.finished_test()
881
        self.assertEqual(None, result)
882
883
    def test_parent_relative(self):
884
        transport = MemoryTransport()
885
        client = FakeClient(transport.base)
886
        client.add_expected_call(
887
            'Branch.get_stacked_on_url', ('kwaak/',),
888
            'error', ('NotStacked',))
889
        client.add_expected_call(
890
            'Branch.get_parent', ('kwaak/',),
4083.1.7 by Andrew Bennetts
Fix same trivial bug [(x) != (x,)] in test_remote and test_smart.
891
            'success', ('../foo/',))
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
892
        transport.mkdir('kwaak')
893
        transport = transport.clone('kwaak')
894
        branch = self.make_remote_branch(transport, client)
895
        result = branch.get_parent()
896
        self.assertEqual(transport.clone('../foo').base, result)
897
898
    def test_parent_absolute(self):
899
        transport = MemoryTransport()
900
        client = FakeClient(transport.base)
901
        client.add_expected_call(
902
            'Branch.get_stacked_on_url', ('kwaak/',),
903
            'error', ('NotStacked',))
904
        client.add_expected_call(
905
            'Branch.get_parent', ('kwaak/',),
4083.1.7 by Andrew Bennetts
Fix same trivial bug [(x) != (x,)] in test_remote and test_smart.
906
            'success', ('http://foo/',))
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
907
        transport.mkdir('kwaak')
908
        transport = transport.clone('kwaak')
909
        branch = self.make_remote_branch(transport, client)
910
        result = branch.get_parent()
911
        self.assertEqual('http://foo/', result)
4288.1.7 by Robert Collins
Add new remote server verb Branch.set_parent_location, dropping roundtrips further on push operations.
912
        client.finished_test()
913
914
915
class TestBranchSetParentLocation(RemoteBranchTestCase):
916
917
    def test_no_parent(self):
918
        # We call the verb when setting parent to None
919
        transport = MemoryTransport()
920
        client = FakeClient(transport.base)
921
        client.add_expected_call(
922
            'Branch.get_stacked_on_url', ('quack/',),
923
            'error', ('NotStacked',))
924
        client.add_expected_call(
925
            'Branch.set_parent_location', ('quack/', 'b', 'r', ''),
926
            'success', ())
927
        transport.mkdir('quack')
928
        transport = transport.clone('quack')
929
        branch = self.make_remote_branch(transport, client)
930
        branch._lock_token = 'b'
931
        branch._repo_lock_token = 'r'
932
        branch._set_parent_location(None)
933
        client.finished_test()
934
935
    def test_parent(self):
936
        transport = MemoryTransport()
937
        client = FakeClient(transport.base)
938
        client.add_expected_call(
939
            'Branch.get_stacked_on_url', ('kwaak/',),
940
            'error', ('NotStacked',))
941
        client.add_expected_call(
942
            'Branch.set_parent_location', ('kwaak/', 'b', 'r', 'foo'),
943
            'success', ())
944
        transport.mkdir('kwaak')
945
        transport = transport.clone('kwaak')
946
        branch = self.make_remote_branch(transport, client)
947
        branch._lock_token = 'b'
948
        branch._repo_lock_token = 'r'
949
        branch._set_parent_location('foo')
950
        client.finished_test()
951
952
    def test_backwards_compat(self):
953
        self.setup_smart_server_with_call_log()
954
        branch = self.make_branch('.')
955
        self.reset_smart_call_log()
956
        verb = 'Branch.set_parent_location'
957
        self.disable_verb(verb)
958
        branch.set_parent('http://foo/')
959
        self.assertLength(12, self.hpss_calls)
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
960
961
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
962
class TestBranchGetTagsBytes(RemoteBranchTestCase):
963
964
    def test_backwards_compat(self):
965
        self.setup_smart_server_with_call_log()
966
        branch = self.make_branch('.')
967
        self.reset_smart_call_log()
968
        verb = 'Branch.get_tags_bytes'
969
        self.disable_verb(verb)
970
        branch.tags.get_tag_dict()
971
        call_count = len([call for call in self.hpss_calls if
972
            call.call.method == verb])
973
        self.assertEqual(1, call_count)
974
975
    def test_trivial(self):
976
        transport = MemoryTransport()
977
        client = FakeClient(transport.base)
978
        client.add_expected_call(
979
            'Branch.get_stacked_on_url', ('quack/',),
980
            'error', ('NotStacked',))
981
        client.add_expected_call(
982
            'Branch.get_tags_bytes', ('quack/',),
983
            'success', ('',))
984
        transport.mkdir('quack')
985
        transport = transport.clone('quack')
986
        branch = self.make_remote_branch(transport, client)
987
        result = branch.tags.get_tag_dict()
988
        client.finished_test()
989
        self.assertEqual({}, result)
990
991
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
992
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
993
994
    def test_empty_branch(self):
995
        # in an empty branch we decode the response properly
996
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
997
        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
998
        client.add_expected_call(
999
            'Branch.get_stacked_on_url', ('quack/',),
1000
            'error', ('NotStacked',))
1001
        client.add_expected_call(
1002
            'Branch.last_revision_info', ('quack/',),
1003
            'success', ('ok', '0', 'null:'))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1004
        transport.mkdir('quack')
1005
        transport = transport.clone('quack')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1006
        branch = self.make_remote_branch(transport, client)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1007
        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
1008
        client.finished_test()
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1009
        self.assertEqual((0, NULL_REVISION), result)
1010
1011
    def test_non_empty_branch(self):
1012
        # 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.
1013
        revid = u'\xc8'.encode('utf8')
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1014
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1015
        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
1016
        client.add_expected_call(
1017
            'Branch.get_stacked_on_url', ('kwaak/',),
1018
            'error', ('NotStacked',))
1019
        client.add_expected_call(
1020
            'Branch.last_revision_info', ('kwaak/',),
1021
            'success', ('ok', '2', revid))
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1022
        transport.mkdir('kwaak')
1023
        transport = transport.clone('kwaak')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1024
        branch = self.make_remote_branch(transport, client)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1025
        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.
1026
        self.assertEqual((2, revid), result)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1027
1028
4053.1.2 by Robert Collins
Actually make this branch work.
1029
class TestBranch_get_stacked_on_url(TestRemote):
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
1030
    """Test Branch._get_stacked_on_url rpc"""
1031
3691.2.10 by Martin Pool
Update more test_remote tests
1032
    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.
1033
        # test that asking for a stacked on url the server can't access works.
1034
        # This isn't perfect, but then as we're in the same process there
1035
        # really isn't anything we can do to be 100% sure that the server
1036
        # doesn't just open in - this test probably needs to be rewritten using
1037
        # a spawn()ed server.
1038
        stacked_branch = self.make_branch('stacked', format='1.9')
1039
        memory_branch = self.make_branch('base', format='1.9')
1040
        vfs_url = self.get_vfs_only_url('base')
1041
        stacked_branch.set_stacked_on_url(vfs_url)
1042
        transport = stacked_branch.bzrdir.root_transport
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
1043
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1044
        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.
1045
            'Branch.get_stacked_on_url', ('stacked/',),
1046
            'success', ('ok', vfs_url))
1047
        # XXX: Multiple calls are bad, this second call documents what is
1048
        # today.
1049
        client.add_expected_call(
1050
            'Branch.get_stacked_on_url', ('stacked/',),
1051
            'success', ('ok', vfs_url))
1052
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1053
            _client=client)
4118.1.5 by Andrew Bennetts
Fix test_remote tests.
1054
        repo_fmt = remote.RemoteRepositoryFormat()
1055
        repo_fmt._custom_format = stacked_branch.repository._format
1056
        branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
1057
            _client=client)
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
1058
        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.
1059
        self.assertEqual(vfs_url, result)
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
1060
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
1061
    def test_backwards_compatible(self):
1062
        # like with bzr1.6 with no Branch.get_stacked_on_url rpc
1063
        base_branch = self.make_branch('base', format='1.6')
1064
        stacked_branch = self.make_branch('stacked', format='1.6')
1065
        stacked_branch.set_stacked_on_url('../base')
1066
        client = FakeClient(self.get_url())
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
1067
        branch_network_name = self.get_branch_format().network_name()
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
1068
        client.add_expected_call(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
1069
            'BzrDir.open_branchV2', ('stacked/',),
1070
            'success', ('branch', branch_network_name))
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
1071
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
1072
            'BzrDir.find_repositoryV3', ('stacked/',),
4118.1.5 by Andrew Bennetts
Fix test_remote tests.
1073
            'success', ('ok', '', 'no', 'no', 'yes',
4053.1.2 by Robert Collins
Actually make this branch work.
1074
                stacked_branch.repository._format.network_name()))
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
1075
        # called twice, once from constructor and then again by us
1076
        client.add_expected_call(
1077
            'Branch.get_stacked_on_url', ('stacked/',),
1078
            'unknown', ('Branch.get_stacked_on_url',))
1079
        client.add_expected_call(
1080
            'Branch.get_stacked_on_url', ('stacked/',),
1081
            'unknown', ('Branch.get_stacked_on_url',))
1082
        # this will also do vfs access, but that goes direct to the transport
1083
        # 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.
1084
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1085
            remote.RemoteBzrDirFormat(), _client=client)
3691.2.12 by Martin Pool
Add test for coping without Branch.get_stacked_on_url
1086
        branch = bzrdir.open_branch()
1087
        result = branch.get_stacked_on_url()
1088
        self.assertEqual('../base', result)
1089
        client.finished_test()
1090
        # it's in the fallback list both for the RemoteRepository and its vfs
1091
        # repository
1092
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1093
        self.assertEqual(1,
1094
            len(branch.repository._real_repository._fallback_repositories))
1095
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1096
    def test_get_stacked_on_real_branch(self):
1097
        base_branch = self.make_branch('base', format='1.6')
1098
        stacked_branch = self.make_branch('stacked', format='1.6')
1099
        stacked_branch.set_stacked_on_url('../base')
4053.1.2 by Robert Collins
Actually make this branch work.
1100
        reference_format = self.get_repo_format()
1101
        network_name = reference_format.network_name()
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1102
        client = FakeClient(self.get_url())
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
1103
        branch_network_name = self.get_branch_format().network_name()
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1104
        client.add_expected_call(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
1105
            'BzrDir.open_branchV2', ('stacked/',),
1106
            'success', ('branch', branch_network_name))
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1107
        client.add_expected_call(
4053.1.2 by Robert Collins
Actually make this branch work.
1108
            'BzrDir.find_repositoryV3', ('stacked/',),
4118.1.5 by Andrew Bennetts
Fix test_remote tests.
1109
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1110
        # called twice, once from constructor and then again by us
1111
        client.add_expected_call(
1112
            'Branch.get_stacked_on_url', ('stacked/',),
1113
            'success', ('ok', '../base'))
1114
        client.add_expected_call(
1115
            'Branch.get_stacked_on_url', ('stacked/',),
1116
            '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.
1117
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1118
            remote.RemoteBzrDirFormat(), _client=client)
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1119
        branch = bzrdir.open_branch()
1120
        result = branch.get_stacked_on_url()
1121
        self.assertEqual('../base', result)
1122
        client.finished_test()
4226.1.2 by Robert Collins
Fix test_remote failing because of less _real_repository objects.
1123
        # it's in the fallback list both for the RemoteRepository.
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1124
        self.assertEqual(1, len(branch.repository._fallback_repositories))
4226.1.2 by Robert Collins
Fix test_remote failing because of less _real_repository objects.
1125
        # And we haven't had to construct a real repository.
1126
        self.assertEqual(None, branch.repository._real_repository)
3691.2.11 by Martin Pool
More tests around RemoteBranch stacking.
1127
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
1128
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1129
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.
1130
1131
    def test_set_empty(self):
1132
        # set_revision_history([]) is translated to calling
1133
        # Branch.set_last_revision(path, '') on the wire.
3104.4.2 by Andrew Bennetts
All tests passing.
1134
        transport = MemoryTransport()
1135
        transport.mkdir('branch')
1136
        transport = transport.clone('branch')
1137
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1138
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1139
        client.add_expected_call(
1140
            'Branch.get_stacked_on_url', ('branch/',),
1141
            'error', ('NotStacked',))
1142
        client.add_expected_call(
1143
            'Branch.lock_write', ('branch/', '', ''),
1144
            'success', ('ok', 'branch token', 'repo token'))
1145
        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.
1146
            'Branch.last_revision_info',
1147
            ('branch/',),
1148
            'success', ('ok', '0', 'null:'))
1149
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1150
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
1151
            'success', ('ok',))
1152
        client.add_expected_call(
1153
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1154
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1155
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1156
        # This is a hack to work around the problem that RemoteBranch currently
1157
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1158
        branch._ensure_real = lambda: None
1159
        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.
1160
        result = branch.set_revision_history([])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1161
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
1162
        self.assertEqual(None, result)
3691.2.10 by Martin Pool
Update more test_remote tests
1163
        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.
1164
1165
    def test_set_nonempty(self):
1166
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1167
        # Branch.set_last_revision(path, rev-idN) on the wire.
3104.4.2 by Andrew Bennetts
All tests passing.
1168
        transport = MemoryTransport()
1169
        transport.mkdir('branch')
1170
        transport = transport.clone('branch')
1171
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1172
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1173
        client.add_expected_call(
1174
            'Branch.get_stacked_on_url', ('branch/',),
1175
            'error', ('NotStacked',))
1176
        client.add_expected_call(
1177
            'Branch.lock_write', ('branch/', '', ''),
1178
            'success', ('ok', 'branch token', 'repo token'))
1179
        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.
1180
            'Branch.last_revision_info',
1181
            ('branch/',),
1182
            'success', ('ok', '0', 'null:'))
1183
        lines = ['rev-id2']
1184
        encoded_body = bz2.compress('\n'.join(lines))
1185
        client.add_success_response_with_body(encoded_body, 'ok')
1186
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1187
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
1188
            'success', ('ok',))
1189
        client.add_expected_call(
1190
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1191
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1192
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1193
        # This is a hack to work around the problem that RemoteBranch currently
1194
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1195
        branch._ensure_real = lambda: None
1196
        # Lock the branch, reset the record of remote calls.
1197
        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.
1198
        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.
1199
        branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
1200
        self.assertEqual(None, result)
3691.2.10 by Martin Pool
Update more test_remote tests
1201
        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.
1202
1203
    def test_no_such_revision(self):
1204
        transport = MemoryTransport()
1205
        transport.mkdir('branch')
1206
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1207
        # A response of 'NoSuchRevision' is translated into an exception.
1208
        client = FakeClient(transport.base)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1209
        client.add_expected_call(
1210
            'Branch.get_stacked_on_url', ('branch/',),
1211
            'error', ('NotStacked',))
1212
        client.add_expected_call(
1213
            'Branch.lock_write', ('branch/', '', ''),
1214
            'success', ('ok', 'branch token', 'repo token'))
1215
        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.
1216
            'Branch.last_revision_info',
1217
            ('branch/',),
1218
            'success', ('ok', '0', 'null:'))
1219
        # get_graph calls to construct the revision history, for the set_rh
1220
        # hook
1221
        lines = ['rev-id']
1222
        encoded_body = bz2.compress('\n'.join(lines))
1223
        client.add_success_response_with_body(encoded_body, 'ok')
1224
        client.add_expected_call(
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1225
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1226
            'error', ('NoSuchRevision', 'rev-id'))
1227
        client.add_expected_call(
1228
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1229
            'success', ('ok',))
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
1230
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1231
        branch = self.make_remote_branch(transport, client)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1232
        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.
1233
        self.assertRaises(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
1234
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1235
        branch.unlock()
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1236
        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.
1237
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1238
    def test_tip_change_rejected(self):
1239
        """TipChangeRejected responses cause a TipChangeRejected exception to
1240
        be raised.
1241
        """
1242
        transport = MemoryTransport()
1243
        transport.mkdir('branch')
1244
        transport = transport.clone('branch')
1245
        client = FakeClient(transport.base)
1246
        rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1247
        rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
3691.2.10 by Martin Pool
Update more test_remote tests
1248
        client.add_expected_call(
1249
            'Branch.get_stacked_on_url', ('branch/',),
1250
            'error', ('NotStacked',))
1251
        client.add_expected_call(
1252
            'Branch.lock_write', ('branch/', '', ''),
1253
            'success', ('ok', 'branch token', 'repo token'))
1254
        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.
1255
            'Branch.last_revision_info',
1256
            ('branch/',),
1257
            'success', ('ok', '0', 'null:'))
1258
        lines = ['rev-id']
1259
        encoded_body = bz2.compress('\n'.join(lines))
1260
        client.add_success_response_with_body(encoded_body, 'ok')
1261
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1262
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1263
            'error', ('TipChangeRejected', rejection_msg_utf8))
1264
        client.add_expected_call(
1265
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1266
            'success', ('ok',))
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1267
        branch = self.make_remote_branch(transport, client)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1268
        branch._ensure_real = lambda: None
1269
        branch.lock_write()
1270
        # The 'TipChangeRejected' error response triggered by calling
1271
        # set_revision_history causes a TipChangeRejected exception.
1272
        err = self.assertRaises(
1273
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1274
        # The UTF-8 message from the response has been decoded into a unicode
1275
        # object.
1276
        self.assertIsInstance(err.msg, unicode)
1277
        self.assertEqual(rejection_msg_unicode, err.msg)
3691.2.10 by Martin Pool
Update more test_remote tests
1278
        branch.unlock()
1279
        client.finished_test()
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1280
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
1281
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1282
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1283
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1284
    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.
1285
        # set_last_revision_info(num, 'rev-id') is translated to calling
1286
        # 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'.
1287
        transport = MemoryTransport()
1288
        transport.mkdir('branch')
1289
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1290
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1291
        # get_stacked_on_url
1292
        client.add_error_response('NotStacked')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1293
        # lock_write
1294
        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.
1295
        # query the current revision
1296
        client.add_success_response('ok', '0', 'null:')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1297
        # set_last_revision
1298
        client.add_success_response('ok')
1299
        # unlock
1300
        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.
1301
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1302
        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.
1303
        # Lock the branch, reset the record of remote calls.
1304
        branch.lock_write()
1305
        client._calls = []
1306
        result = branch.set_last_revision_info(1234, 'a-revision-id')
1307
        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.
1308
            [('call', 'Branch.last_revision_info', ('branch/',)),
1309
             ('call', 'Branch.set_last_revision_info',
3297.4.1 by Andrew Bennetts
Merge 'Add Branch.set_last_revision_info smart method'.
1310
                ('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.
1311
                 '1234', 'a-revision-id'))],
1312
            client._calls)
1313
        self.assertEqual(None, result)
1314
1315
    def test_no_such_revision(self):
1316
        # A response of 'NoSuchRevision' is translated into an exception.
1317
        transport = MemoryTransport()
1318
        transport.mkdir('branch')
1319
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1320
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1321
        # get_stacked_on_url
1322
        client.add_error_response('NotStacked')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1323
        # lock_write
1324
        client.add_success_response('ok', 'branch token', 'repo token')
1325
        # set_last_revision
1326
        client.add_error_response('NoSuchRevision', 'revid')
1327
        # unlock
1328
        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.
1329
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1330
        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.
1331
        # Lock the branch, reset the record of remote calls.
1332
        branch.lock_write()
1333
        client._calls = []
1334
1335
        self.assertRaises(
1336
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1337
        branch.unlock()
1338
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1339
    def lock_remote_branch(self, branch):
1340
        """Trick a RemoteBranch into thinking it is locked."""
1341
        branch._lock_mode = 'w'
1342
        branch._lock_count = 2
1343
        branch._lock_token = 'branch token'
1344
        branch._repo_lock_token = 'repo token'
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1345
        branch.repository._lock_mode = 'w'
1346
        branch.repository._lock_count = 2
1347
        branch.repository._lock_token = 'repo token'
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1348
1349
    def test_backwards_compatibility(self):
1350
        """If the server does not support the Branch.set_last_revision_info
1351
        verb (which is new in 1.4), then the client falls back to VFS methods.
1352
        """
1353
        # This test is a little messy.  Unlike most tests in this file, it
1354
        # doesn't purely test what a Remote* object sends over the wire, and
1355
        # how it reacts to responses from the wire.  It instead relies partly
1356
        # on asserting that the RemoteBranch will call
1357
        # self._real_branch.set_last_revision_info(...).
1358
1359
        # First, set up our RemoteBranch with a FakeClient that raises
1360
        # UnknownSmartMethod, and a StubRealBranch that logs how it is called.
1361
        transport = MemoryTransport()
1362
        transport.mkdir('branch')
1363
        transport = transport.clone('branch')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1364
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1365
        client.add_expected_call(
1366
            'Branch.get_stacked_on_url', ('branch/',),
1367
            'error', ('NotStacked',))
1368
        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.
1369
            'Branch.last_revision_info',
1370
            ('branch/',),
1371
            'success', ('ok', '0', 'null:'))
1372
        client.add_expected_call(
3691.2.10 by Martin Pool
Update more test_remote tests
1373
            'Branch.set_last_revision_info',
1374
            ('branch/', 'branch token', 'repo token', '1234', 'a-revision-id',),
1375
            'unknown', 'Branch.set_last_revision_info')
1376
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1377
        branch = self.make_remote_branch(transport, client)
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1378
        class StubRealBranch(object):
1379
            def __init__(self):
1380
                self.calls = []
1381
            def set_last_revision_info(self, revno, revision_id):
1382
                self.calls.append(
1383
                    ('set_last_revision_info', revno, revision_id))
3441.5.5 by Andrew Bennetts
Some small tweaks and comments.
1384
            def _clear_cached_state(self):
1385
                pass
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1386
        real_branch = StubRealBranch()
1387
        branch._real_branch = real_branch
1388
        self.lock_remote_branch(branch)
1389
1390
        # Call set_last_revision_info, and verify it behaved as expected.
1391
        result = branch.set_last_revision_info(1234, 'a-revision-id')
1392
        self.assertEqual(
1393
            [('set_last_revision_info', 1234, 'a-revision-id')],
1394
            real_branch.calls)
3691.2.10 by Martin Pool
Update more test_remote tests
1395
        client.finished_test()
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
1396
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1397
    def test_unexpected_error(self):
3697.2.6 by Martin Pool
Merge 261315 fix into 1.7 branch
1398
        # If the server sends an error the client doesn't understand, it gets
1399
        # turned into an UnknownErrorFromSmartServer, which is presented as a
1400
        # non-internal error to the user.
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1401
        transport = MemoryTransport()
1402
        transport.mkdir('branch')
1403
        transport = transport.clone('branch')
1404
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1405
        # get_stacked_on_url
1406
        client.add_error_response('NotStacked')
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1407
        # lock_write
1408
        client.add_success_response('ok', 'branch token', 'repo token')
1409
        # set_last_revision
1410
        client.add_error_response('UnexpectedError')
1411
        # unlock
1412
        client.add_success_response('ok')
1413
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1414
        branch = self.make_remote_branch(transport, client)
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1415
        # Lock the branch, reset the record of remote calls.
1416
        branch.lock_write()
1417
        client._calls = []
1418
1419
        err = self.assertRaises(
3690.1.2 by Andrew Bennetts
Rename UntranslateableErrorFromSmartServer -> UnknownErrorFromSmartServer.
1420
            errors.UnknownErrorFromSmartServer,
3245.4.53 by Andrew Bennetts
Add some missing 'raise' statements to test_remote.
1421
            branch.set_last_revision_info, 123, 'revid')
1422
        self.assertEqual(('UnexpectedError',), err.error_tuple)
1423
        branch.unlock()
1424
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1425
    def test_tip_change_rejected(self):
1426
        """TipChangeRejected responses cause a TipChangeRejected exception to
1427
        be raised.
1428
        """
1429
        transport = MemoryTransport()
1430
        transport.mkdir('branch')
1431
        transport = transport.clone('branch')
1432
        client = FakeClient(transport.base)
3691.2.10 by Martin Pool
Update more test_remote tests
1433
        # get_stacked_on_url
1434
        client.add_error_response('NotStacked')
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1435
        # lock_write
1436
        client.add_success_response('ok', 'branch token', 'repo token')
1437
        # set_last_revision
1438
        client.add_error_response('TipChangeRejected', 'rejection message')
1439
        # unlock
1440
        client.add_success_response('ok')
1441
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1442
        branch = self.make_remote_branch(transport, client)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
1443
        # Lock the branch, reset the record of remote calls.
1444
        branch.lock_write()
1445
        self.addCleanup(branch.unlock)
1446
        client._calls = []
1447
1448
        # The 'TipChangeRejected' error response triggered by calling
1449
        # set_last_revision_info causes a TipChangeRejected exception.
1450
        err = self.assertRaises(
1451
            errors.TipChangeRejected,
1452
            branch.set_last_revision_info, 123, 'revid')
1453
        self.assertEqual('rejection message', err.msg)
1454
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
1455
4226.2.1 by Robert Collins
Set branch config options via a smart method.
1456
class TestBranchGetSetConfig(RemoteBranchTestCase):
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
1457
1458
    def test_get_branch_conf(self):
4226.1.5 by Robert Collins
Reinstate the use of the Branch.get_config_file verb.
1459
        # in an empty branch we decode the response properly
1460
        client = FakeClient()
1461
        client.add_expected_call(
1462
            'Branch.get_stacked_on_url', ('memory:///',),
1463
            'error', ('NotStacked',),)
1464
        client.add_success_response_with_body('# config file body', 'ok')
1465
        transport = MemoryTransport()
1466
        branch = self.make_remote_branch(transport, client)
1467
        config = branch.get_config()
1468
        config.has_explicit_nickname()
1469
        self.assertEqual(
1470
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1471
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1472
            client._calls)
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
1473
4241.5.2 by Matt Nordhoff
Add a test
1474
    def test_get_multi_line_branch_conf(self):
1475
        # Make sure that multiple-line branch.conf files are supported
1476
        #
1477
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1478
        client = FakeClient()
1479
        client.add_expected_call(
1480
            'Branch.get_stacked_on_url', ('memory:///',),
1481
            'error', ('NotStacked',),)
1482
        client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
1483
        transport = MemoryTransport()
1484
        branch = self.make_remote_branch(transport, client)
1485
        config = branch.get_config()
1486
        self.assertEqual(u'2', config.get_user_option('b'))
1487
4226.2.1 by Robert Collins
Set branch config options via a smart method.
1488
    def test_set_option(self):
1489
        client = FakeClient()
1490
        client.add_expected_call(
1491
            'Branch.get_stacked_on_url', ('memory:///',),
1492
            'error', ('NotStacked',),)
1493
        client.add_expected_call(
1494
            'Branch.lock_write', ('memory:///', '', ''),
1495
            'success', ('ok', 'branch token', 'repo token'))
1496
        client.add_expected_call(
1497
            'Branch.set_config_option', ('memory:///', 'branch token',
1498
            'repo token', 'foo', 'bar', ''),
1499
            'success', ())
1500
        client.add_expected_call(
1501
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1502
            'success', ('ok',))
1503
        transport = MemoryTransport()
1504
        branch = self.make_remote_branch(transport, client)
1505
        branch.lock_write()
1506
        config = branch._get_config()
1507
        config.set_option('foo', 'bar')
1508
        branch.unlock()
1509
        client.finished_test()
1510
1511
    def test_backwards_compat_set_option(self):
1512
        self.setup_smart_server_with_call_log()
1513
        branch = self.make_branch('.')
1514
        verb = 'Branch.set_config_option'
1515
        self.disable_verb(verb)
1516
        branch.lock_write()
1517
        self.addCleanup(branch.unlock)
1518
        self.reset_smart_call_log()
1519
        branch._get_config().set_option('value', 'name')
1520
        self.assertLength(10, self.hpss_calls)
1521
        self.assertEqual('value', branch._get_config().get_option('name'))
1522
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
1523
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1524
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.
1525
1526
    def test_lock_write_unlockable(self):
1527
        transport = MemoryTransport()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1528
        client = FakeClient(transport.base)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1529
        client.add_expected_call(
1530
            'Branch.get_stacked_on_url', ('quack/',),
1531
            'error', ('NotStacked',),)
1532
        client.add_expected_call(
1533
            'Branch.lock_write', ('quack/', '', ''),
1534
            '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.
1535
        transport.mkdir('quack')
1536
        transport = transport.clone('quack')
3692.1.1 by Andrew Bennetts
Make RemoteBranch.lock_write lock the repository too.
1537
        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.
1538
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
3691.2.9 by Martin Pool
Convert and update more test_remote tests
1539
        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.
1540
1541
4288.1.1 by Robert Collins
Add support for a RemoteBzrDirConfig to support optimising push operations which need to look for default stacking locations.
1542
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1543
1544
    def test__get_config(self):
1545
        client = FakeClient()
1546
        client.add_success_response_with_body('default_stack_on = /\n', 'ok')
1547
        transport = MemoryTransport()
1548
        bzrdir = self.make_remote_bzrdir(transport, client)
1549
        config = bzrdir.get_config()
1550
        self.assertEqual('/', config.get_default_stack_on())
1551
        self.assertEqual(
1552
            [('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
1553
            client._calls)
1554
1555
    def test_set_option_uses_vfs(self):
1556
        self.setup_smart_server_with_call_log()
1557
        bzrdir = self.make_bzrdir('.')
1558
        self.reset_smart_call_log()
1559
        config = bzrdir.get_config()
1560
        config.set_default_stack_on('/')
1561
        self.assertLength(3, self.hpss_calls)
1562
1563
    def test_backwards_compat_get_option(self):
1564
        self.setup_smart_server_with_call_log()
1565
        bzrdir = self.make_bzrdir('.')
1566
        verb = 'BzrDir.get_config_file'
4288.1.2 by Robert Collins
Create a server verb for doing BzrDir.get_config()
1567
        self.disable_verb(verb)
4288.1.1 by Robert Collins
Add support for a RemoteBzrDirConfig to support optimising push operations which need to look for default stacking locations.
1568
        self.reset_smart_call_log()
1569
        self.assertEqual(None,
1570
            bzrdir._get_config().get_option('default_stack_on'))
1571
        self.assertLength(3, self.hpss_calls)
1572
1573
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1574
class TestTransportIsReadonly(tests.TestCase):
1575
1576
    def test_true(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1577
        client = FakeClient()
1578
        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.
1579
        transport = RemoteTransport('bzr://example.com/', medium=False,
1580
                                    _client=client)
1581
        self.assertEqual(True, transport.is_readonly())
1582
        self.assertEqual(
1583
            [('call', 'Transport.is_readonly', ())],
1584
            client._calls)
1585
1586
    def test_false(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1587
        client = FakeClient()
1588
        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.
1589
        transport = RemoteTransport('bzr://example.com/', medium=False,
1590
                                    _client=client)
1591
        self.assertEqual(False, transport.is_readonly())
1592
        self.assertEqual(
1593
            [('call', 'Transport.is_readonly', ())],
1594
            client._calls)
1595
1596
    def test_error_from_old_server(self):
1597
        """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
1598
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1599
        Clients should treat it as a "no" response, because is_readonly is only
1600
        advisory anyway (a transport could be read-write, but then the
1601
        underlying filesystem could be readonly anyway).
1602
        """
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1603
        client = FakeClient()
1604
        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.
1605
        transport = RemoteTransport('bzr://example.com/', medium=False,
1606
                                    _client=client)
1607
        self.assertEqual(False, transport.is_readonly())
1608
        self.assertEqual(
1609
            [('call', 'Transport.is_readonly', ())],
1610
            client._calls)
1611
2466.2.2 by Andrew Bennetts
Add tests for RemoteTransport.is_readonly in the style of the other remote object tests.
1612
3840.1.1 by Andrew Bennetts
Fix RemoteTransport's translation of errors involving paths; it wasn't passing orig_path to _translate_error.
1613
class TestTransportMkdir(tests.TestCase):
1614
1615
    def test_permissiondenied(self):
1616
        client = FakeClient()
1617
        client.add_error_response('PermissionDenied', 'remote path', 'extra')
1618
        transport = RemoteTransport('bzr://example.com/', medium=False,
1619
                                    _client=client)
1620
        exc = self.assertRaises(
1621
            errors.PermissionDenied, transport.mkdir, 'client path')
1622
        expected_error = errors.PermissionDenied('/client path', 'extra')
1623
        self.assertEqual(expected_error, exc)
1624
1625
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
1626
class TestRemoteSSHTransportAuthentication(tests.TestCaseInTempDir):
1627
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
1628
    def test_defaults_to_none(self):
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
1629
        t = RemoteSSHTransport('bzr+ssh://example.com')
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
1630
        self.assertIs(None, t._get_credentials()[0])
3777.1.3 by Aaron Bentley
Use SSH default username from authentication.conf
1631
1632
    def test_uses_authentication_config(self):
1633
        conf = config.AuthenticationConfig()
1634
        conf._get_config().update(
1635
            {'bzr+sshtest': {'scheme': 'ssh', 'user': 'bar', 'host':
1636
            'example.com'}})
1637
        conf._save()
1638
        t = RemoteSSHTransport('bzr+ssh://example.com')
1639
        self.assertEqual('bar', t._get_credentials()[0])
1640
1641
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
1642
class TestRemoteRepository(TestRemote):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
1643
    """Base for testing RemoteRepository protocol usage.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1644
1645
    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
1646
    what is sent or expected to be require a thoughtful update to these tests
1647
    because they might break compatibility with different-versioned servers.
1648
    """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1649
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1650
    def setup_fake_client_and_repository(self, transport_path):
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1651
        """Create the fake client and repository for testing with.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1652
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1653
        There's no real server here; we just have canned responses sent
1654
        back one by one.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1655
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
1656
        :param transport_path: Path below the root of the MemoryTransport
1657
            where the repository will be created.
1658
        """
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1659
        transport = MemoryTransport()
1660
        transport.mkdir(transport_path)
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1661
        client = FakeClient(transport.base)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1662
        transport = transport.clone(transport_path)
1663
        # 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.
1664
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1665
            _client=False)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
1666
        repo = RemoteRepository(bzrdir, None, _client=client)
1667
        return repo, client
1668
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
1669
4183.5.1 by Robert Collins
Add RepositoryFormat.fast_deltas to signal fast delta creation.
1670
class TestRepositoryFormat(TestRemoteRepository):
1671
1672
    def test_fast_delta(self):
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
1673
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
4183.5.1 by Robert Collins
Add RepositoryFormat.fast_deltas to signal fast delta creation.
1674
        true_format = RemoteRepositoryFormat()
1675
        true_format._network_name = true_name
1676
        self.assertEqual(True, true_format.fast_deltas)
1677
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
1678
        false_format = RemoteRepositoryFormat()
1679
        false_format._network_name = false_name
1680
        self.assertEqual(False, false_format.fast_deltas)
1681
1682
2018.12.2 by Andrew Bennetts
Remove some duplicate code in test_remote
1683
class TestRepositoryGatherStats(TestRemoteRepository):
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1684
1685
    def test_revid_none(self):
1686
        # ('ok',), body with revisions and size
1687
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1688
        repo, client = self.setup_fake_client_and_repository(transport_path)
1689
        client.add_success_response_with_body(
1690
            'revisions: 2\nsize: 18\n', 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1691
        result = repo.gather_stats(None)
1692
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1693
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1694
             ('quack/','','no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1695
            client._calls)
1696
        self.assertEqual({'revisions': 2, 'size': 18}, result)
1697
1698
    def test_revid_no_committers(self):
1699
        # ('ok',), body without committers
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1700
        body = ('firstrev: 123456.300 3600\n'
1701
                'latestrev: 654231.400 0\n'
1702
                'revisions: 2\n'
1703
                'size: 18\n')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1704
        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.
1705
        revid = u'\xc8'.encode('utf8')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1706
        repo, client = self.setup_fake_client_and_repository(transport_path)
1707
        client.add_success_response_with_body(body, 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1708
        result = repo.gather_stats(revid)
1709
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1710
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1711
              ('quick/', revid, 'no'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1712
            client._calls)
1713
        self.assertEqual({'revisions': 2, 'size': 18,
1714
                          'firstrev': (123456.300, 3600),
1715
                          'latestrev': (654231.400, 0),},
1716
                         result)
1717
1718
    def test_revid_with_committers(self):
1719
        # ('ok',), body with committers
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1720
        body = ('committers: 128\n'
1721
                'firstrev: 123456.300 3600\n'
1722
                'latestrev: 654231.400 0\n'
1723
                'revisions: 2\n'
1724
                'size: 18\n')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1725
        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.
1726
        revid = u'\xc8'.encode('utf8')
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1727
        repo, client = self.setup_fake_client_and_repository(transport_path)
1728
        client.add_success_response_with_body(body, 'ok')
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1729
        result = repo.gather_stats(revid, True)
1730
        self.assertEqual(
2018.5.153 by Andrew Bennetts
Rename call2 to call_expecting_body, and other small changes prompted by review.
1731
            [('call_expecting_body', 'Repository.gather_stats',
3104.4.2 by Andrew Bennetts
All tests passing.
1732
              ('buick/', revid, 'yes'))],
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
1733
            client._calls)
1734
        self.assertEqual({'revisions': 2, 'size': 18,
1735
                          'committers': 128,
1736
                          'firstrev': (123456.300, 3600),
1737
                          'latestrev': (654231.400, 0),},
1738
                         result)
1739
1740
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1741
class TestRepositoryGetGraph(TestRemoteRepository):
1742
1743
    def test_get_graph(self):
3835.1.6 by Aaron Bentley
Reduce inefficiency when doing make_parents_provider frequently
1744
        # 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.
1745
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1746
        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.
1747
        graph = repo.get_graph()
3835.1.6 by Aaron Bentley
Reduce inefficiency when doing make_parents_provider frequently
1748
        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.
1749
1750
1751
class TestRepositoryGetParentMap(TestRemoteRepository):
1752
1753
    def test_get_parent_map_caching(self):
1754
        # get_parent_map returns from cache until unlock()
1755
        # setup a reponse with two revisions
1756
        r1 = u'\u0e33'.encode('utf8')
1757
        r2 = u'\u0dab'.encode('utf8')
1758
        lines = [' '.join([r2, r1]), r1]
3211.5.2 by Robert Collins
Change RemoteRepository.get_parent_map to use bz2 not gzip for compression.
1759
        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.
1760
1761
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1762
        repo, client = self.setup_fake_client_and_repository(transport_path)
1763
        client.add_success_response_with_body(encoded_body, 'ok')
1764
        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.
1765
        repo.lock_read()
1766
        graph = repo.get_graph()
1767
        parents = graph.get_parent_map([r2])
1768
        self.assertEqual({r2: (r1,)}, parents)
1769
        # locking and unlocking deeper should not reset
1770
        repo.lock_read()
1771
        repo.unlock()
1772
        parents = graph.get_parent_map([r1])
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
1773
        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.
1774
        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.
1775
            [('call_with_body_bytes_expecting_body',
4190.1.6 by Robert Collins
Missed some unit tests.
1776
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1777
              '\n\n0')],
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1778
            client._calls)
1779
        repo.unlock()
1780
        # now we call again, and it should use the second response.
1781
        repo.lock_read()
1782
        graph = repo.get_graph()
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
1783
        parents = graph.get_parent_map([r1])
1784
        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.
1785
        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.
1786
            [('call_with_body_bytes_expecting_body',
4190.1.6 by Robert Collins
Missed some unit tests.
1787
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1788
              '\n\n0'),
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.
1789
             ('call_with_body_bytes_expecting_body',
4190.1.6 by Robert Collins
Missed some unit tests.
1790
              'Repository.get_parent_map', ('quack/', 'include-missing:', r1),
1791
              '\n\n0'),
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1792
            ],
1793
            client._calls)
1794
        repo.unlock()
1795
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1796
    def test_get_parent_map_reconnects_if_unknown_method(self):
1797
        transport_path = 'quack'
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1798
        rev_id = 'revision-id'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1799
        repo, client = self.setup_fake_client_and_repository(transport_path)
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1800
        client.add_unknown_method_response('Repository.get_parent_map')
1801
        client.add_success_response_with_body(rev_id, 'ok')
3453.4.10 by Andrew Bennetts
Change _is_remote_at_least to _is_remote_before.
1802
        self.assertFalse(client._medium._is_remote_before((1, 2)))
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1803
        parents = 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.
1804
        self.assertEqual(
3213.1.8 by Andrew Bennetts
Merge from bzr.dev.
1805
            [('call_with_body_bytes_expecting_body',
4190.1.6 by Robert Collins
Missed some unit tests.
1806
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1807
              rev_id), '\n\n0'),
3213.1.2 by Andrew Bennetts
Add test for reconnection if get_parent_map is unknown by the server.
1808
             ('disconnect medium',),
1809
             ('call_expecting_body', 'Repository.get_revision_graph',
1810
              ('quack/', ''))],
1811
            client._calls)
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1812
        # 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.
1813
        self.assertTrue(client._medium._is_remote_before((1, 2)))
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1814
        self.assertEqual({rev_id: ('null:',)}, parents)
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1815
1816
    def test_get_parent_map_fallback_parentless_node(self):
1817
        """get_parent_map falls back to get_revision_graph on old servers.  The
1818
        results from get_revision_graph are tweaked to match the get_parent_map
1819
        API.
1820
3389.1.3 by Andrew Bennetts
Remove XXX from test description.
1821
        Specifically, a {key: ()} result from get_revision_graph means "no
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1822
        parents" for that key, which in get_parent_map results should be
3389.1.3 by Andrew Bennetts
Remove XXX from test description.
1823
        represented as {key: ('null:',)}.
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1824
1825
        This is the test for https://bugs.launchpad.net/bzr/+bug/214894
1826
        """
1827
        rev_id = 'revision-id'
1828
        transport_path = 'quack'
3245.4.40 by Andrew Bennetts
Merge from bzr.dev.
1829
        repo, client = self.setup_fake_client_and_repository(transport_path)
1830
        client.add_success_response_with_body(rev_id, 'ok')
3453.4.9 by Andrew Bennetts
Rename _remote_is_not to _remember_remote_is_before.
1831
        client._medium._remember_remote_is_before((1, 2))
3948.3.7 by Martin Pool
Updated tests for RemoteRepository.get_parent_map on old servers.
1832
        parents = repo.get_parent_map([rev_id])
3389.1.2 by Andrew Bennetts
Add test for the bug John found.
1833
        self.assertEqual(
1834
            [('call_expecting_body', 'Repository.get_revision_graph',
1835
             ('quack/', ''))],
1836
            client._calls)
1837
        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.
1838
3297.2.3 by Andrew Bennetts
Test the code path that the typo is on.
1839
    def test_get_parent_map_unexpected_response(self):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
1840
        repo, client = self.setup_fake_client_and_repository('path')
1841
        client.add_success_response('something unexpected!')
3297.2.3 by Andrew Bennetts
Test the code path that the typo is on.
1842
        self.assertRaises(
1843
            errors.UnexpectedSmartServerResponse,
1844
            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.
1845
4190.1.1 by Robert Collins
Negatively cache misses during read-locks in RemoteRepository.
1846
    def test_get_parent_map_negative_caches_missing_keys(self):
1847
        self.setup_smart_server_with_call_log()
1848
        repo = self.make_repository('foo')
1849
        self.assertIsInstance(repo, RemoteRepository)
1850
        repo.lock_read()
1851
        self.addCleanup(repo.unlock)
1852
        self.reset_smart_call_log()
1853
        graph = repo.get_graph()
1854
        self.assertEqual({},
1855
            graph.get_parent_map(['some-missing', 'other-missing']))
1856
        self.assertLength(1, self.hpss_calls)
1857
        # No call if we repeat this
1858
        self.reset_smart_call_log()
1859
        graph = repo.get_graph()
1860
        self.assertEqual({},
1861
            graph.get_parent_map(['some-missing', 'other-missing']))
1862
        self.assertLength(0, self.hpss_calls)
1863
        # Asking for more unknown keys makes a request.
1864
        self.reset_smart_call_log()
1865
        graph = repo.get_graph()
1866
        self.assertEqual({},
1867
            graph.get_parent_map(['some-missing', 'other-missing',
1868
                'more-missing']))
1869
        self.assertLength(1, self.hpss_calls)
1870
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1871
    def disableExtraResults(self):
1872
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
1873
        SmartServerRepositoryGetParentMap.no_extra_results = True
1874
        def reset_values():
1875
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
1876
        self.addCleanup(reset_values)
1877
4214.2.5 by Andrew Bennetts
Fix the bug.
1878
    def test_null_cached_missing_and_stop_key(self):
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1879
        self.setup_smart_server_with_call_log()
4214.2.4 by Andrew Bennetts
Further simplify the test to reproduce the bug.
1880
        # Make a branch with a single revision.
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1881
        builder = self.make_branch_builder('foo')
1882
        builder.start_series()
1883
        builder.build_snapshot('first', None, [
1884
            ('add', ('', 'root-id', 'directory', ''))])
1885
        builder.finish_series()
1886
        branch = builder.get_branch()
1887
        repo = branch.repository
1888
        self.assertIsInstance(repo, RemoteRepository)
4214.2.3 by Andrew Bennetts
Further simplify test case, and add more comments.
1889
        # Stop the server from sending extra results.
1890
        self.disableExtraResults()
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1891
        repo.lock_read()
1892
        self.addCleanup(repo.unlock)
1893
        self.reset_smart_call_log()
1894
        graph = repo.get_graph()
4214.2.4 by Andrew Bennetts
Further simplify the test to reproduce the bug.
1895
        # Query for 'first' and 'null:'.  Because 'null:' is a parent of
4214.2.5 by Andrew Bennetts
Fix the bug.
1896
        # 'first' it will be a candidate for the stop_keys of subsequent
1897
        # requests, and because 'null:' was queried but not returned it will be
1898
        # cached as missing.
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1899
        self.assertEqual({'first': ('null:',)},
4214.2.4 by Andrew Bennetts
Further simplify the test to reproduce the bug.
1900
            graph.get_parent_map(['first', 'null:']))
1901
        # Now query for another key.  This request will pass along a recipe of
1902
        # start and stop keys describing the already cached results, and this
4214.2.5 by Andrew Bennetts
Fix the bug.
1903
        # recipe's revision count must be correct (or else it will trigger an
4214.2.4 by Andrew Bennetts
Further simplify the test to reproduce the bug.
1904
        # error from the server).
4214.2.5 by Andrew Bennetts
Fix the bug.
1905
        self.assertEqual({}, graph.get_parent_map(['another-key']))
4214.2.3 by Andrew Bennetts
Further simplify test case, and add more comments.
1906
        # This assertion guards against disableExtraResults silently failing to
1907
        # work, thus invalidating the test.
4214.2.4 by Andrew Bennetts
Further simplify the test to reproduce the bug.
1908
        self.assertLength(2, self.hpss_calls)
4214.2.1 by Andrew Bennetts
A long but failing test for the get_parent_map RPC bug.
1909
4190.1.4 by Robert Collins
Cache ghosts when we can get them from a RemoteRepository in get_parent_map.
1910
    def test_get_parent_map_gets_ghosts_from_result(self):
1911
        # asking for a revision should negatively cache close ghosts in its
1912
        # ancestry.
1913
        self.setup_smart_server_with_call_log()
1914
        tree = self.make_branch_and_memory_tree('foo')
1915
        tree.lock_write()
1916
        try:
1917
            builder = treebuilder.TreeBuilder()
1918
            builder.start_tree(tree)
1919
            builder.build([])
1920
            builder.finish_tree()
1921
            tree.set_parent_ids(['non-existant'], allow_leftmost_as_ghost=True)
1922
            rev_id = tree.commit('')
1923
        finally:
1924
            tree.unlock()
1925
        tree.lock_read()
1926
        self.addCleanup(tree.unlock)
1927
        repo = tree.branch.repository
1928
        self.assertIsInstance(repo, RemoteRepository)
1929
        # ask for rev_id
1930
        repo.get_parent_map([rev_id])
1931
        self.reset_smart_call_log()
1932
        # Now asking for rev_id's ghost parent should not make calls
1933
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
1934
        self.assertLength(0, self.hpss_calls)
1935
3172.5.4 by Robert Collins
Implement get_parent_map for RemoteRepository with caching, based on get_revision_graph.
1936
3835.1.15 by Aaron Bentley
Allow miss caching to be disabled.
1937
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
1938
1939
    def test_allows_new_revisions(self):
1940
        """get_parent_map's results can be updated by commit."""
1941
        smart_server = server.SmartTCPServer_for_testing()
1942
        smart_server.setUp()
1943
        self.addCleanup(smart_server.tearDown)
1944
        self.make_branch('branch')
1945
        branch = Branch.open(smart_server.get_url() + '/branch')
1946
        tree = branch.create_checkout('tree', lightweight=True)
1947
        tree.lock_write()
1948
        self.addCleanup(tree.unlock)
1949
        graph = tree.branch.repository.get_graph()
1950
        # This provides an opportunity for the missing rev-id to be cached.
1951
        self.assertEqual({}, graph.get_parent_map(['rev1']))
1952
        tree.commit('message', rev_id='rev1')
1953
        graph = tree.branch.repository.get_graph()
1954
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
1955
1956
3948.3.9 by Martin Pool
Undelete TestRepositoryGetRevisionGraph but make it use private client methods to simulate old clients
1957
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
1958
1959
    def test_null_revision(self):
1960
        # a null revision has the predictable result {}, we should have no wire
1961
        # traffic when calling it with this argument
1962
        transport_path = 'empty'
1963
        repo, client = self.setup_fake_client_and_repository(transport_path)
1964
        client.add_success_response('notused')
1965
        # actual RemoteRepository.get_revision_graph is gone, but there's an
1966
        # equivalent private method for testing
1967
        result = repo._get_revision_graph(NULL_REVISION)
1968
        self.assertEqual([], client._calls)
1969
        self.assertEqual({}, result)
1970
1971
    def test_none_revision(self):
1972
        # with none we want the entire graph
1973
        r1 = u'\u0e33'.encode('utf8')
1974
        r2 = u'\u0dab'.encode('utf8')
1975
        lines = [' '.join([r2, r1]), r1]
1976
        encoded_body = '\n'.join(lines)
1977
1978
        transport_path = 'sinhala'
1979
        repo, client = self.setup_fake_client_and_repository(transport_path)
1980
        client.add_success_response_with_body(encoded_body, 'ok')
1981
        # actual RemoteRepository.get_revision_graph is gone, but there's an
1982
        # equivalent private method for testing
1983
        result = repo._get_revision_graph(None)
1984
        self.assertEqual(
1985
            [('call_expecting_body', 'Repository.get_revision_graph',
1986
             ('sinhala/', ''))],
1987
            client._calls)
1988
        self.assertEqual({r1: (), r2: (r1, )}, result)
1989
1990
    def test_specific_revision(self):
1991
        # with a specific revision we want the graph for that
1992
        # with none we want the entire graph
1993
        r11 = u'\u0e33'.encode('utf8')
1994
        r12 = u'\xc9'.encode('utf8')
1995
        r2 = u'\u0dab'.encode('utf8')
1996
        lines = [' '.join([r2, r11, r12]), r11, r12]
1997
        encoded_body = '\n'.join(lines)
1998
1999
        transport_path = 'sinhala'
2000
        repo, client = self.setup_fake_client_and_repository(transport_path)
2001
        client.add_success_response_with_body(encoded_body, 'ok')
2002
        result = repo._get_revision_graph(r2)
2003
        self.assertEqual(
2004
            [('call_expecting_body', 'Repository.get_revision_graph',
2005
             ('sinhala/', r2))],
2006
            client._calls)
2007
        self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2008
2009
    def test_no_such_revision(self):
2010
        revid = '123'
2011
        transport_path = 'sinhala'
2012
        repo, client = self.setup_fake_client_and_repository(transport_path)
2013
        client.add_error_response('nosuchrevision', revid)
2014
        # also check that the right revision is reported in the error
2015
        self.assertRaises(errors.NoSuchRevision,
2016
            repo._get_revision_graph, revid)
2017
        self.assertEqual(
2018
            [('call_expecting_body', 'Repository.get_revision_graph',
2019
             ('sinhala/', revid))],
2020
            client._calls)
2021
2022
    def test_unexpected_error(self):
2023
        revid = '123'
2024
        transport_path = 'sinhala'
2025
        repo, client = self.setup_fake_client_and_repository(transport_path)
2026
        client.add_error_response('AnUnexpectedError')
2027
        e = self.assertRaises(errors.UnknownErrorFromSmartServer,
2028
            repo._get_revision_graph, revid)
2029
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
2030
2031
4419.2.7 by Andrew Bennetts
Add unit tests for RemoteRepository.get_rev_id_for_revno.
2032
class TestRepositoryGetRevIdForRevno(TestRemoteRepository):
2033
2034
    def test_ok(self):
4419.2.8 by Andrew Bennetts
Add unit test for RemoteRepository.get_rev_id_for_revno using fallbacks if it gets a history-incomplete response.
2035
        repo, client = self.setup_fake_client_and_repository('quack')
4419.2.7 by Andrew Bennetts
Add unit tests for RemoteRepository.get_rev_id_for_revno.
2036
        client.add_expected_call(
2037
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2038
            'success', ('ok', 'rev-five'))
2039
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2040
        self.assertEqual((True, 'rev-five'), result)
2041
        client.finished_test()
2042
2043
    def test_history_incomplete(self):
4419.2.8 by Andrew Bennetts
Add unit test for RemoteRepository.get_rev_id_for_revno using fallbacks if it gets a history-incomplete response.
2044
        repo, client = self.setup_fake_client_and_repository('quack')
4419.2.7 by Andrew Bennetts
Add unit tests for RemoteRepository.get_rev_id_for_revno.
2045
        client.add_expected_call(
2046
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2047
            'success', ('history-incomplete', 10, 'rev-ten'))
2048
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2049
        self.assertEqual((False, (10, 'rev-ten')), result)
2050
        client.finished_test()
2051
4419.2.8 by Andrew Bennetts
Add unit test for RemoteRepository.get_rev_id_for_revno using fallbacks if it gets a history-incomplete response.
2052
    def test_history_incomplete_with_fallback(self):
2053
        """A 'history-incomplete' response causes the fallback repository to be
2054
        queried too, if one is set.
2055
        """
2056
        # Make a repo with a fallback repo, both using a FakeClient.
2057
        format = remote.response_tuple_to_repo_format(
2058
            ('yes', 'no', 'yes', 'fake-network-name'))
2059
        repo, client = self.setup_fake_client_and_repository('quack')
2060
        repo._format = format
2061
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2062
            'fallback')
2063
        fallback_repo._client = client
2064
        repo.add_fallback_repository(fallback_repo)
2065
        # First the client should ask the primary repo
2066
        client.add_expected_call(
2067
            'Repository.get_rev_id_for_revno', ('quack/', 1, (42, 'rev-foo')),
2068
            'success', ('history-incomplete', 2, 'rev-two'))
2069
        # Then it should ask the fallback, using revno/revid from the
2070
        # history-incomplete response as the known revno/revid.
2071
        client.add_expected_call(
2072
            'Repository.get_rev_id_for_revno',('fallback/', 1, (2, 'rev-two')),
2073
            'success', ('ok', 'rev-one'))
2074
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2075
        self.assertEqual((True, 'rev-one'), result)
2076
        client.finished_test()
2077
4419.2.7 by Andrew Bennetts
Add unit tests for RemoteRepository.get_rev_id_for_revno.
2078
    def test_nosuchrevision(self):
2079
        # 'nosuchrevision' is returned when the known-revid is not found in the
2080
        # remote repo.  The client translates that response to NoSuchRevision.
4419.2.8 by Andrew Bennetts
Add unit test for RemoteRepository.get_rev_id_for_revno using fallbacks if it gets a history-incomplete response.
2081
        repo, client = self.setup_fake_client_and_repository('quack')
4419.2.7 by Andrew Bennetts
Add unit tests for RemoteRepository.get_rev_id_for_revno.
2082
        client.add_expected_call(
2083
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2084
            'error', ('nosuchrevision', 'rev-foo'))
2085
        self.assertRaises(
2086
            errors.NoSuchRevision,
2087
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2088
        client.finished_test()
2089
2090
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
2091
class TestRepositoryIsShared(TestRemoteRepository):
2092
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
2093
    def test_is_shared(self):
2094
        # ('yes', ) for Repository.is_shared -> 'True'.
2095
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2096
        repo, client = self.setup_fake_client_and_repository(transport_path)
2097
        client.add_success_response('yes')
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
2098
        result = repo.is_shared()
2099
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2100
            [('call', 'Repository.is_shared', ('quack/',))],
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
2101
            client._calls)
2102
        self.assertEqual(True, result)
2103
2104
    def test_is_not_shared(self):
2105
        # ('no', ) for Repository.is_shared -> 'False'.
2106
        transport_path = 'qwack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2107
        repo, client = self.setup_fake_client_and_repository(transport_path)
2108
        client.add_success_response('no')
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
2109
        result = repo.is_shared()
2110
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2111
            [('call', 'Repository.is_shared', ('qwack/',))],
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
2112
            client._calls)
2113
        self.assertEqual(False, result)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2114
2115
2116
class TestRepositoryLockWrite(TestRemoteRepository):
2117
2118
    def test_lock_write(self):
2119
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2120
        repo, client = self.setup_fake_client_and_repository(transport_path)
2121
        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
2122
        result = repo.lock_write()
2123
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2124
            [('call', 'Repository.lock_write', ('quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2125
            client._calls)
2126
        self.assertEqual('a token', result)
2127
2128
    def test_lock_write_already_locked(self):
2129
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2130
        repo, client = self.setup_fake_client_and_repository(transport_path)
2131
        client.add_error_response('LockContention')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2132
        self.assertRaises(errors.LockContention, repo.lock_write)
2133
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2134
            [('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.
2135
            client._calls)
2136
2137
    def test_lock_write_unlockable(self):
2138
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2139
        repo, client = self.setup_fake_client_and_repository(transport_path)
2140
        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.
2141
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2142
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2143
            [('call', 'Repository.lock_write', ('quack/', ''))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2144
            client._calls)
2145
2146
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
2147
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2148
2149
    def test_backwards_compat(self):
2150
        self.setup_smart_server_with_call_log()
2151
        repo = self.make_repository('.')
2152
        self.reset_smart_call_log()
2153
        verb = 'Repository.set_make_working_trees'
2154
        self.disable_verb(verb)
2155
        repo.set_make_working_trees(True)
2156
        call_count = len([call for call in self.hpss_calls if
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
2157
            call.call.method == verb])
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
2158
        self.assertEqual(1, call_count)
2159
2160
    def test_current(self):
2161
        transport_path = 'quack'
2162
        repo, client = self.setup_fake_client_and_repository(transport_path)
2163
        client.add_expected_call(
2164
            'Repository.set_make_working_trees', ('quack/', 'True'),
2165
            'success', ('ok',))
2166
        client.add_expected_call(
2167
            'Repository.set_make_working_trees', ('quack/', 'False'),
2168
            'success', ('ok',))
2169
        repo.set_make_working_trees(True)
2170
        repo.set_make_working_trees(False)
2171
2172
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2173
class TestRepositoryUnlock(TestRemoteRepository):
2174
2175
    def test_unlock(self):
2176
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2177
        repo, client = self.setup_fake_client_and_repository(transport_path)
2178
        client.add_success_response('ok', 'a token')
2179
        client.add_success_response('ok')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2180
        repo.lock_write()
2181
        repo.unlock()
2182
        self.assertEqual(
3104.4.2 by Andrew Bennetts
All tests passing.
2183
            [('call', 'Repository.lock_write', ('quack/', '')),
2184
             ('call', 'Repository.unlock', ('quack/', 'a token'))],
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2185
            client._calls)
2186
2187
    def test_unlock_wrong_token(self):
2188
        # If somehow the token is wrong, unlock will raise TokenMismatch.
2189
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2190
        repo, client = self.setup_fake_client_and_repository(transport_path)
2191
        client.add_success_response('ok', 'a token')
2192
        client.add_error_response('TokenMismatch')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
2193
        repo.lock_write()
2194
        self.assertRaises(errors.TokenMismatch, repo.unlock)
2195
2196
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
2197
class TestRepositoryHasRevision(TestRemoteRepository):
2198
2199
    def test_none(self):
2200
        # repo.has_revision(None) should not cause any traffic.
2201
        transport_path = 'quack'
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2202
        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.
2203
2204
        # The null revision is always there, so has_revision(None) == True.
3172.3.3 by Robert Collins
Missed one occurence of None -> NULL_REVISION.
2205
        self.assertEqual(True, repo.has_revision(NULL_REVISION))
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
2206
2207
        # The remote repo shouldn't be accessed.
2208
        self.assertEqual([], client._calls)
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
2209
2210
4144.3.2 by Andrew Bennetts
Use Repository.insert_stream_locked if there is a lock_token for the remote repo.
2211
class TestRepositoryInsertStream(TestRemoteRepository):
4476.3.32 by Andrew Bennetts
Move disable_verb into base TestCase to remove duplication, fix trivial test failures due to new insert_stream verb in test_remote (and also add some trivial tests for the new verb).
2212
    """Tests for using Repository.insert_stream verb when the _1.18 variant is
2213
    not available.
2214
2215
    This test case is very similar to TestRepositoryInsertStream_1_18.
2216
    """
2217
2218
    def setUp(self):
2219
        TestRemoteRepository.setUp(self)
2220
        self.disable_verb('Repository.insert_stream_1.18')
2221
2222
    def test_unlocked_repo(self):
2223
        transport_path = 'quack'
2224
        repo, client = self.setup_fake_client_and_repository(transport_path)
2225
        client.add_expected_call(
2226
            'Repository.insert_stream_1.18', ('quack/', ''),
2227
            'unknown', ('Repository.insert_stream_1.18',))
2228
        client.add_expected_call(
2229
            'Repository.insert_stream', ('quack/', ''),
2230
            'success', ('ok',))
2231
        client.add_expected_call(
2232
            'Repository.insert_stream', ('quack/', ''),
2233
            'success', ('ok',))
2234
        sink = repo._get_sink()
2235
        fmt = repository.RepositoryFormat.get_default_format()
2236
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2237
        self.assertEqual([], resume_tokens)
2238
        self.assertEqual(set(), missing_keys)
2239
        client.finished_test()
2240
2241
    def test_locked_repo_with_no_lock_token(self):
2242
        transport_path = 'quack'
2243
        repo, client = self.setup_fake_client_and_repository(transport_path)
2244
        client.add_expected_call(
2245
            'Repository.lock_write', ('quack/', ''),
2246
            'success', ('ok', ''))
2247
        client.add_expected_call(
2248
            'Repository.insert_stream_1.18', ('quack/', ''),
2249
            'unknown', ('Repository.insert_stream_1.18',))
2250
        client.add_expected_call(
2251
            'Repository.insert_stream', ('quack/', ''),
2252
            'success', ('ok',))
2253
        client.add_expected_call(
2254
            'Repository.insert_stream', ('quack/', ''),
2255
            'success', ('ok',))
2256
        repo.lock_write()
2257
        sink = repo._get_sink()
2258
        fmt = repository.RepositoryFormat.get_default_format()
2259
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2260
        self.assertEqual([], resume_tokens)
2261
        self.assertEqual(set(), missing_keys)
2262
        client.finished_test()
2263
2264
    def test_locked_repo_with_lock_token(self):
2265
        transport_path = 'quack'
2266
        repo, client = self.setup_fake_client_and_repository(transport_path)
2267
        client.add_expected_call(
2268
            'Repository.lock_write', ('quack/', ''),
2269
            'success', ('ok', 'a token'))
2270
        client.add_expected_call(
2271
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
2272
            'unknown', ('Repository.insert_stream_1.18',))
2273
        client.add_expected_call(
2274
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2275
            'success', ('ok',))
2276
        client.add_expected_call(
2277
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2278
            'success', ('ok',))
2279
        repo.lock_write()
2280
        sink = repo._get_sink()
2281
        fmt = repository.RepositoryFormat.get_default_format()
2282
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2283
        self.assertEqual([], resume_tokens)
2284
        self.assertEqual(set(), missing_keys)
2285
        client.finished_test()
2286
4476.3.36 by Andrew Bennetts
Add a somewhat complex test to exercise the fallback-to-vfs logic in RemoteSink when an inventory-delta is encountered and the 1.18 verb isn't accepted.
2287
    def test_stream_with_inventory_delta(self):
2288
        """inventory-delta records can't be sent to the
2289
        Repository.insert_stream verb.  So when one is encountered the
2290
        RemoteSink immediately stops using that verb and falls back to VFS
2291
        insert_stream.
2292
        """
2293
        transport_path = 'quack'
2294
        repo, client = self.setup_fake_client_and_repository(transport_path)
2295
        client.add_expected_call(
2296
            'Repository.insert_stream_1.18', ('quack/', ''),
2297
            'unknown', ('Repository.insert_stream_1.18',))
2298
        client.add_expected_call(
2299
            'Repository.insert_stream', ('quack/', ''),
2300
            'success', ('ok',))
2301
        client.add_expected_call(
2302
            'Repository.insert_stream', ('quack/', ''),
2303
            'success', ('ok',))
2304
        # Create a fake real repository for insert_stream to fall back on, so
2305
        # that we can directly see the records the RemoteSink passes to the
2306
        # real sink.
2307
        class FakeRealSink:
2308
            def __init__(self):
2309
                self.records = []
2310
            def insert_stream(self, stream, src_format, resume_tokens):
2311
                for substream_kind, substream in stream:
2312
                    self.records.append(
2313
                        (substream_kind, [record.key for record in substream]))
2314
                return ['fake tokens'], ['fake missing keys']
2315
        fake_real_sink = FakeRealSink()
2316
        class FakeRealRepository:
2317
            def _get_sink(self):
2318
                return fake_real_sink
2319
        repo._real_repository = FakeRealRepository()
2320
        sink = repo._get_sink()
2321
        fmt = repository.RepositoryFormat.get_default_format()
2322
        stream = self.make_stream_with_inv_deltas(fmt)
2323
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2324
        # Every record from the first inventory delta should have been sent to
2325
        # the VFS sink.
2326
        expected_records = [
2327
            ('inventories', [('rev2',), ('rev3',)]),
2328
            ('texts', [('some-rev', 'some-file')])]
2329
        self.assertEqual(expected_records, fake_real_sink.records)
2330
        # The return values from the real sink's insert_stream are propagated
2331
        # back to the original caller.
2332
        self.assertEqual(['fake tokens'], resume_tokens)
2333
        self.assertEqual(['fake missing keys'], missing_keys)
2334
        client.finished_test()
2335
2336
    def make_stream_with_inv_deltas(self, fmt):
2337
        """Make a simple stream with an inventory delta followed by more
2338
        records and more substreams to test that all records and substreams
2339
        from that point on are used.
2340
2341
        This sends, in order:
2342
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
2343
             inventory-deltas.
2344
           * texts substream: (some-rev, some-file)
2345
        """
2346
        # Define a stream using generators so that it isn't rewindable.
2347
        def stream_with_inv_delta():
2348
            yield ('inventories', inventory_substream_with_delta())
2349
            yield ('texts', [
2350
                versionedfile.FulltextContentFactory(
2351
                    ('some-rev', 'some-file'), (), None, 'content')])
2352
        def inventory_substream_with_delta():
2353
            # An empty inventory fulltext.  This will be streamed normally.
2354
            inv = inventory.Inventory(revision_id='rev1')
2355
            text = fmt._serializer.write_inventory_to_string(inv)
2356
            yield versionedfile.FulltextContentFactory(
2357
                ('rev1',), (), None, text)
2358
            # An inventory delta.  This can't be streamed via this verb, so it
2359
            # will trigger a fallback to VFS insert_stream.
2360
            entry = inv.make_entry(
2361
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
2362
            delta = [(None, 'newdir', 'newdir-id', entry)]
2363
            yield versionedfile.InventoryDeltaContentFactory(
2364
                ('rev2',), (('rev1',)), None, ('rev1',), (True, False), None)
2365
            # Another delta.
2366
            yield versionedfile.InventoryDeltaContentFactory(
2367
                ('rev3',), (('rev1',)), None, ('rev1',), (True, False), None)
2368
        return stream_with_inv_delta()
2369
4476.3.32 by Andrew Bennetts
Move disable_verb into base TestCase to remove duplication, fix trivial test failures due to new insert_stream verb in test_remote (and also add some trivial tests for the new verb).
2370
2371
class TestRepositoryInsertStream_1_18(TestRemoteRepository):
2372
2373
    def test_unlocked_repo(self):
2374
        transport_path = 'quack'
2375
        repo, client = self.setup_fake_client_and_repository(transport_path)
2376
        client.add_expected_call(
2377
            'Repository.insert_stream_1.18', ('quack/', ''),
2378
            'success', ('ok',))
2379
        client.add_expected_call(
2380
            'Repository.insert_stream_1.18', ('quack/', ''),
2381
            'success', ('ok',))
2382
        sink = repo._get_sink()
2383
        fmt = repository.RepositoryFormat.get_default_format()
2384
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2385
        self.assertEqual([], resume_tokens)
2386
        self.assertEqual(set(), missing_keys)
2387
        client.finished_test()
2388
2389
    def test_locked_repo_with_no_lock_token(self):
2390
        transport_path = 'quack'
2391
        repo, client = self.setup_fake_client_and_repository(transport_path)
2392
        client.add_expected_call(
2393
            'Repository.lock_write', ('quack/', ''),
2394
            'success', ('ok', ''))
2395
        client.add_expected_call(
2396
            'Repository.insert_stream_1.18', ('quack/', ''),
2397
            'success', ('ok',))
2398
        client.add_expected_call(
2399
            'Repository.insert_stream_1.18', ('quack/', ''),
2400
            'success', ('ok',))
2401
        repo.lock_write()
2402
        sink = repo._get_sink()
2403
        fmt = repository.RepositoryFormat.get_default_format()
2404
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2405
        self.assertEqual([], resume_tokens)
2406
        self.assertEqual(set(), missing_keys)
2407
        client.finished_test()
2408
2409
    def test_locked_repo_with_lock_token(self):
2410
        transport_path = 'quack'
2411
        repo, client = self.setup_fake_client_and_repository(transport_path)
2412
        client.add_expected_call(
2413
            'Repository.lock_write', ('quack/', ''),
2414
            'success', ('ok', 'a token'))
2415
        client.add_expected_call(
2416
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
2417
            'success', ('ok',))
2418
        client.add_expected_call(
2419
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
4144.3.2 by Andrew Bennetts
Use Repository.insert_stream_locked if there is a lock_token for the remote repo.
2420
            'success', ('ok',))
2421
        repo.lock_write()
2422
        sink = repo._get_sink()
2423
        fmt = repository.RepositoryFormat.get_default_format()
2424
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2425
        self.assertEqual([], resume_tokens)
2426
        self.assertEqual(set(), missing_keys)
2427
        client.finished_test()
2428
2429
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
2430
class TestRepositoryTarball(TestRemoteRepository):
2431
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
2432
    # This is a canned tarball reponse we can validate against
2018.18.18 by Martin Pool
reformat
2433
    tarball_content = (
2018.18.23 by Martin Pool
review cleanups
2434
        'QlpoOTFBWSZTWdGkj3wAAWF/k8aQACBIB//A9+8cIX/v33AACEAYABAECEACNz'
2435
        'JqsgJJFPTSnk1A3qh6mTQAAAANPUHkagkSTEkaA09QaNAAAGgAAAcwCYCZGAEY'
2436
        'mJhMJghpiaYBUkKammSHqNMZQ0NABkNAeo0AGneAevnlwQoGzEzNVzaYxp/1Uk'
2437
        'xXzA1CQX0BJMZZLcPBrluJir5SQyijWHYZ6ZUtVqqlYDdB2QoCwa9GyWwGYDMA'
2438
        'OQYhkpLt/OKFnnlT8E0PmO8+ZNSo2WWqeCzGB5fBXZ3IvV7uNJVE7DYnWj6qwB'
2439
        'k5DJDIrQ5OQHHIjkS9KqwG3mc3t+F1+iujb89ufyBNIKCgeZBWrl5cXxbMGoMs'
2440
        'c9JuUkg5YsiVcaZJurc6KLi6yKOkgCUOlIlOpOoXyrTJjK8ZgbklReDdwGmFgt'
2441
        'dkVsAIslSVCd4AtACSLbyhLHryfb14PKegrVDba+U8OL6KQtzdM5HLjAc8/p6n'
2442
        '0lgaWU8skgO7xupPTkyuwheSckejFLK5T4ZOo0Gda9viaIhpD1Qn7JqqlKAJqC'
2443
        'QplPKp2nqBWAfwBGaOwVrz3y1T+UZZNismXHsb2Jq18T+VaD9k4P8DqE3g70qV'
2444
        'JLurpnDI6VS5oqDDPVbtVjMxMxMg4rzQVipn2Bv1fVNK0iq3Gl0hhnnHKm/egy'
2445
        'nWQ7QH/F3JFOFCQ0aSPfA='
2446
        ).decode('base64')
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
2447
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
2448
    def test_repository_tarball(self):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
2449
        # Test that Repository.tarball generates the right operations
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
2450
        transport_path = 'repo'
2018.18.14 by Martin Pool
merge hpss again; restore incorrectly removed RemoteRepository.break_lock
2451
        expected_calls = [('call_expecting_body', 'Repository.tarball',
3104.4.2 by Andrew Bennetts
All tests passing.
2452
                           ('repo/', 'bz2',),),
2018.18.7 by Martin Pool
(broken) Start addng client proxy test for Repository.tarball
2453
            ]
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2454
        repo, client = self.setup_fake_client_and_repository(transport_path)
2455
        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
2456
        # Now actually ask for the tarball
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
2457
        tarball_file = repo._get_tarball('bz2')
2018.18.25 by Martin Pool
Repository.tarball fixes for python2.4
2458
        try:
2459
            self.assertEqual(expected_calls, client._calls)
2460
            self.assertEqual(self.tarball_content, tarball_file.read())
2461
        finally:
2462
            tarball_file.close()
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
2463
2464
2465
class TestRemoteRepositoryCopyContent(tests.TestCaseWithTransport):
2466
    """RemoteRepository.copy_content_into optimizations"""
2467
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
2468
    def test_copy_content_remote_to_local(self):
2469
        self.transport_server = server.SmartTCPServer_for_testing
2470
        src_repo = self.make_repository('repo1')
2471
        src_repo = repository.Repository.open(self.get_url('repo1'))
2472
        # At the moment the tarball-based copy_content_into can't write back
2473
        # into a smart server.  It would be good if it could upload the
2474
        # tarball; once that works we'd have to create repositories of
2475
        # different formats. -- mbp 20070410
2476
        dest_url = self.get_vfs_only_url('repo2')
2477
        dest_bzrdir = BzrDir.create(dest_url)
2478
        dest_repo = dest_bzrdir.create_repository()
2479
        self.assertFalse(isinstance(dest_repo, RemoteRepository))
2480
        self.assertTrue(isinstance(src_repo, RemoteRepository))
2481
        src_repo.copy_content_into(dest_repo)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2482
2483
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2484
class _StubRealPackRepository(object):
2485
2486
    def __init__(self, calls):
4145.1.6 by Robert Collins
More test fallout, but all caught now.
2487
        self.calls = calls
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2488
        self._pack_collection = _StubPackCollection(calls)
2489
4145.1.6 by Robert Collins
More test fallout, but all caught now.
2490
    def is_in_write_group(self):
2491
        return False
2492
2493
    def refresh_data(self):
2494
        self.calls.append(('pack collection reload_pack_names',))
2495
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2496
2497
class _StubPackCollection(object):
2498
2499
    def __init__(self, calls):
2500
        self.calls = calls
2501
2502
    def autopack(self):
2503
        self.calls.append(('pack collection autopack',))
2504
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2505
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2506
class TestRemotePackRepositoryAutoPack(TestRemoteRepository):
2507
    """Tests for RemoteRepository.autopack implementation."""
2508
2509
    def test_ok(self):
2510
        """When the server returns 'ok' and there's no _real_repository, then
2511
        nothing else happens: the autopack method is done.
2512
        """
2513
        transport_path = 'quack'
2514
        repo, client = self.setup_fake_client_and_repository(transport_path)
2515
        client.add_expected_call(
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
2516
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2517
        repo.autopack()
2518
        client.finished_test()
2519
2520
    def test_ok_with_real_repo(self):
2521
        """When the server returns 'ok' and there is a _real_repository, then
2522
        the _real_repository's reload_pack_name's method will be called.
2523
        """
2524
        transport_path = 'quack'
2525
        repo, client = self.setup_fake_client_and_repository(transport_path)
2526
        client.add_expected_call(
2527
            'PackRepository.autopack', ('quack/',),
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
2528
            'success', ('ok',))
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2529
        repo._real_repository = _StubRealPackRepository(client._calls)
2530
        repo.autopack()
2531
        self.assertEqual(
2532
            [('call', 'PackRepository.autopack', ('quack/',)),
3801.1.13 by Andrew Bennetts
Revert returning of pack-names from the RPC.
2533
             ('pack collection reload_pack_names',)],
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2534
            client._calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2535
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2536
    def test_backwards_compatibility(self):
2537
        """If the server does not recognise the PackRepository.autopack verb,
2538
        fallback to the real_repository's implementation.
2539
        """
2540
        transport_path = 'quack'
2541
        repo, client = self.setup_fake_client_and_repository(transport_path)
2542
        client.add_unknown_method_response('PackRepository.autopack')
2543
        def stub_ensure_real():
2544
            client._calls.append(('_ensure_real',))
2545
            repo._real_repository = _StubRealPackRepository(client._calls)
2546
        repo._ensure_real = stub_ensure_real
2547
        repo.autopack()
2548
        self.assertEqual(
2549
            [('call', 'PackRepository.autopack', ('quack/',)),
2550
             ('_ensure_real',),
2551
             ('pack collection autopack',)],
2552
            client._calls)
2553
2554
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2555
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2556
    """Base class for unit tests for bzrlib.remote._translate_error."""
2557
2558
    def translateTuple(self, error_tuple, **context):
2559
        """Call _translate_error with an ErrorFromSmartServer built from the
2560
        given error_tuple.
2561
2562
        :param error_tuple: A tuple of a smart server response, as would be
2563
            passed to an ErrorFromSmartServer.
2564
        :kwargs context: context items to call _translate_error with.
2565
2566
        :returns: The error raised by _translate_error.
2567
        """
2568
        # Raise the ErrorFromSmartServer before passing it as an argument,
2569
        # because _translate_error may need to re-raise it with a bare 'raise'
2570
        # statement.
2571
        server_error = errors.ErrorFromSmartServer(error_tuple)
2572
        translated_error = self.translateErrorFromSmartServer(
2573
            server_error, **context)
2574
        return translated_error
2575
2576
    def translateErrorFromSmartServer(self, error_object, **context):
2577
        """Like translateTuple, but takes an already constructed
2578
        ErrorFromSmartServer rather than a tuple.
2579
        """
2580
        try:
2581
            raise error_object
2582
        except errors.ErrorFromSmartServer, server_error:
2583
            translated_error = self.assertRaises(
2584
                errors.BzrError, remote._translate_error, server_error,
2585
                **context)
2586
        return translated_error
2587
3801.1.4 by Andrew Bennetts
Add tests for autopack RPC.
2588
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2589
class TestErrorTranslationSuccess(TestErrorTranslationBase):
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2590
    """Unit tests for bzrlib.remote._translate_error.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2591
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2592
    Given an ErrorFromSmartServer (which has an error tuple from a smart
2593
    server) and some context, _translate_error raises more specific errors from
2594
    bzrlib.errors.
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2595
2596
    This test case covers the cases where _translate_error succeeds in
2597
    translating an ErrorFromSmartServer to something better.  See
2598
    TestErrorTranslationRobustness for other cases.
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2599
    """
2600
2601
    def test_NoSuchRevision(self):
2602
        branch = self.make_branch('')
2603
        revid = 'revid'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2604
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2605
            ('NoSuchRevision', revid), branch=branch)
2606
        expected_error = errors.NoSuchRevision(branch, revid)
2607
        self.assertEqual(expected_error, translated_error)
2608
2609
    def test_nosuchrevision(self):
2610
        repository = self.make_repository('')
2611
        revid = 'revid'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2612
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2613
            ('nosuchrevision', revid), repository=repository)
2614
        expected_error = errors.NoSuchRevision(repository, revid)
2615
        self.assertEqual(expected_error, translated_error)
2616
2617
    def test_nobranch(self):
2618
        bzrdir = self.make_bzrdir('')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2619
        translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2620
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2621
        self.assertEqual(expected_error, translated_error)
2622
2623
    def test_LockContention(self):
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2624
        translated_error = self.translateTuple(('LockContention',))
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2625
        expected_error = errors.LockContention('(remote lock)')
2626
        self.assertEqual(expected_error, translated_error)
2627
2628
    def test_UnlockableTransport(self):
2629
        bzrdir = self.make_bzrdir('')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2630
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2631
            ('UnlockableTransport',), bzrdir=bzrdir)
2632
        expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2633
        self.assertEqual(expected_error, translated_error)
2634
2635
    def test_LockFailed(self):
2636
        lock = 'str() of a server lock'
2637
        why = 'str() of why'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2638
        translated_error = self.translateTuple(('LockFailed', lock, why))
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2639
        expected_error = errors.LockFailed(lock, why)
2640
        self.assertEqual(expected_error, translated_error)
2641
2642
    def test_TokenMismatch(self):
2643
        token = 'a lock token'
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2644
        translated_error = self.translateTuple(('TokenMismatch',), token=token)
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2645
        expected_error = errors.TokenMismatch(token, '(remote token)')
2646
        self.assertEqual(expected_error, translated_error)
2647
2648
    def test_Diverged(self):
2649
        branch = self.make_branch('a')
2650
        other_branch = self.make_branch('b')
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2651
        translated_error = self.translateTuple(
3533.3.3 by Andrew Bennetts
Add unit tests for bzrlib.remote._translate_error.
2652
            ('Diverged',), branch=branch, other_branch=other_branch)
2653
        expected_error = errors.DivergedBranches(branch, other_branch)
2654
        self.assertEqual(expected_error, translated_error)
2655
3786.4.2 by Andrew Bennetts
Add tests and fix code to make sure ReadError and PermissionDenied are robustly handled by _translate_error.
2656
    def test_ReadError_no_args(self):
2657
        path = 'a path'
2658
        translated_error = self.translateTuple(('ReadError',), path=path)
2659
        expected_error = errors.ReadError(path)
2660
        self.assertEqual(expected_error, translated_error)
2661
2662
    def test_ReadError(self):
2663
        path = 'a path'
2664
        translated_error = self.translateTuple(('ReadError', path))
2665
        expected_error = errors.ReadError(path)
2666
        self.assertEqual(expected_error, translated_error)
2667
2668
    def test_PermissionDenied_no_args(self):
2669
        path = 'a path'
2670
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2671
        expected_error = errors.PermissionDenied(path)
2672
        self.assertEqual(expected_error, translated_error)
2673
2674
    def test_PermissionDenied_one_arg(self):
2675
        path = 'a path'
2676
        translated_error = self.translateTuple(('PermissionDenied', path))
2677
        expected_error = errors.PermissionDenied(path)
2678
        self.assertEqual(expected_error, translated_error)
2679
2680
    def test_PermissionDenied_one_arg_and_context(self):
2681
        """Given a choice between a path from the local context and a path on
2682
        the wire, _translate_error prefers the path from the local context.
2683
        """
2684
        local_path = 'local path'
2685
        remote_path = 'remote path'
2686
        translated_error = self.translateTuple(
2687
            ('PermissionDenied', remote_path), path=local_path)
2688
        expected_error = errors.PermissionDenied(local_path)
2689
        self.assertEqual(expected_error, translated_error)
2690
2691
    def test_PermissionDenied_two_args(self):
2692
        path = 'a path'
2693
        extra = 'a string with extra info'
2694
        translated_error = self.translateTuple(
2695
            ('PermissionDenied', path, extra))
2696
        expected_error = errors.PermissionDenied(path, extra)
2697
        self.assertEqual(expected_error, translated_error)
2698
2699
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2700
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2701
    """Unit tests for bzrlib.remote._translate_error's robustness.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2702
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2703
    TestErrorTranslationSuccess is for cases where _translate_error can
2704
    translate successfully.  This class about how _translate_err behaves when
2705
    it fails to translate: it re-raises the original error.
2706
    """
2707
2708
    def test_unrecognised_server_error(self):
2709
        """If the error code from the server is not recognised, the original
2710
        ErrorFromSmartServer is propagated unmodified.
2711
        """
2712
        error_tuple = ('An unknown error tuple',)
3690.1.2 by Andrew Bennetts
Rename UntranslateableErrorFromSmartServer -> UnknownErrorFromSmartServer.
2713
        server_error = errors.ErrorFromSmartServer(error_tuple)
2714
        translated_error = self.translateErrorFromSmartServer(server_error)
2715
        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.
2716
        self.assertEqual(expected_error, translated_error)
3533.3.4 by Andrew Bennetts
Add tests for _translate_error's robustness.
2717
2718
    def test_context_missing_a_key(self):
2719
        """In case of a bug in the client, or perhaps an unexpected response
2720
        from a server, _translate_error returns the original error tuple from
2721
        the server and mutters a warning.
2722
        """
2723
        # To translate a NoSuchRevision error _translate_error needs a 'branch'
2724
        # in the context dict.  So let's give it an empty context dict instead
2725
        # to exercise its error recovery.
2726
        empty_context = {}
2727
        error_tuple = ('NoSuchRevision', 'revid')
2728
        server_error = errors.ErrorFromSmartServer(error_tuple)
2729
        translated_error = self.translateErrorFromSmartServer(server_error)
2730
        self.assertEqual(server_error, translated_error)
2731
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2732
        # been muttered to the log file for developer to look at.
2733
        self.assertContainsRe(
2734
            self._get_log(keep_log_file=True),
2735
            "Missing key 'branch' in context")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2736
3786.4.2 by Andrew Bennetts
Add tests and fix code to make sure ReadError and PermissionDenied are robustly handled by _translate_error.
2737
    def test_path_missing(self):
2738
        """Some translations (PermissionDenied, ReadError) can determine the
2739
        'path' variable from either the wire or the local context.  If neither
2740
        has it, then an error is raised.
2741
        """
2742
        error_tuple = ('ReadError',)
2743
        server_error = errors.ErrorFromSmartServer(error_tuple)
2744
        translated_error = self.translateErrorFromSmartServer(server_error)
2745
        self.assertEqual(server_error, translated_error)
2746
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2747
        # been muttered to the log file for developer to look at.
2748
        self.assertContainsRe(
2749
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
2750
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2751
2752
class TestStacking(tests.TestCaseWithTransport):
2753
    """Tests for operations on stacked remote repositories.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2754
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2755
    The underlying format type must support stacking.
2756
    """
2757
2758
    def test_access_stacked_remote(self):
2759
        # based on <http://launchpad.net/bugs/261315>
2760
        # make a branch stacked on another repository containing an empty
2761
        # revision, then open it over hpss - we should be able to see that
2762
        # revision.
2763
        base_transport = self.get_transport()
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2764
        base_builder = self.make_branch_builder('base', format='1.9')
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2765
        base_builder.start_series()
2766
        base_revid = base_builder.build_snapshot('rev-id', None,
2767
            [('add', ('', None, 'directory', None))],
2768
            'message')
2769
        base_builder.finish_series()
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2770
        stacked_branch = self.make_branch('stacked', format='1.9')
3691.2.2 by Martin Pool
Fix some problems in access to stacked repositories over hpss (#261315)
2771
        stacked_branch.set_stacked_on_url('../base')
2772
        # start a server looking at this
2773
        smart_server = server.SmartTCPServer_for_testing()
2774
        smart_server.setUp()
2775
        self.addCleanup(smart_server.tearDown)
2776
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2777
        # can get its branch and repository
2778
        remote_branch = remote_bzrdir.open_branch()
2779
        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
2780
        remote_repo.lock_read()
2781
        try:
2782
            # it should have an appropriate fallback repository, which should also
2783
            # be a RemoteRepository
4288.1.2 by Robert Collins
Create a server verb for doing BzrDir.get_config()
2784
            self.assertLength(1, remote_repo._fallback_repositories)
3691.2.6 by Martin Pool
Disable RemoteBranch stacking, but get get_stacked_on_url working, and passing back exceptions
2785
            self.assertIsInstance(remote_repo._fallback_repositories[0],
2786
                RemoteRepository)
2787
            # and it has the revision committed to the underlying repository;
2788
            # these have varying implementations so we try several of them
2789
            self.assertTrue(remote_repo.has_revisions([base_revid]))
2790
            self.assertTrue(remote_repo.has_revision(base_revid))
2791
            self.assertEqual(remote_repo.get_revision(base_revid).message,
2792
                'message')
2793
        finally:
2794
            remote_repo.unlock()
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2795
3835.1.7 by Aaron Bentley
Updates from review
2796
    def prepare_stacked_remote_branch(self):
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2797
        """Get stacked_upon and stacked branches with content in each."""
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2798
        self.setup_smart_server_with_call_log()
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2799
        tree1 = self.make_branch_and_tree('tree1', format='1.9')
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2800
        tree1.commit('rev1', rev_id='rev1')
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2801
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2802
            ).open_workingtree()
2803
        tree2.commit('local changes make me feel good.')
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2804
        branch2 = Branch.open(self.get_url('tree2'))
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2805
        branch2.lock_read()
2806
        self.addCleanup(branch2.unlock)
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2807
        return tree1.branch, branch2
3835.1.7 by Aaron Bentley
Updates from review
2808
2809
    def test_stacked_get_parent_map(self):
2810
        # the public implementation of get_parent_map obeys stacking
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2811
        _, branch = self.prepare_stacked_remote_branch()
3835.1.7 by Aaron Bentley
Updates from review
2812
        repo = branch.repository
3835.1.2 by Aaron Bentley
Add tests for get_parent_map
2813
        self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
3835.1.7 by Aaron Bentley
Updates from review
2814
3835.1.10 by Aaron Bentley
Move CachingExtraParentsProvider to Graph
2815
    def test_unstacked_get_parent_map(self):
2816
        # _unstacked_provider.get_parent_map ignores stacking
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2817
        _, branch = self.prepare_stacked_remote_branch()
3835.1.10 by Aaron Bentley
Move CachingExtraParentsProvider to Graph
2818
        provider = branch.repository._unstacked_provider
3835.1.8 by Aaron Bentley
Make UnstackedParentsProvider manage the cache
2819
        self.assertEqual([], provider.get_parent_map(['rev1']).keys())
3834.3.3 by John Arbash Meinel
Merge bzr.dev, resolve conflict in tests.
2820
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2821
    def fetch_stream_to_rev_order(self, stream):
2822
        result = []
2823
        for kind, substream in stream:
2824
            if not kind == 'revisions':
2825
                list(substream)
2826
            else:
2827
                for content in substream:
2828
                    result.append(content.key[-1])
2829
        return result
2830
2831
    def get_ordered_revs(self, format, order):
2832
        """Get a list of the revisions in a stream to format format.
2833
2834
        :param format: The format of the target.
2835
        :param order: the order that target should have requested.
2836
        :result: The revision ids in the stream, in the order seen,
2837
            the topological order of revisions in the source.
2838
        """
2839
        unordered_format = bzrdir.format_registry.get(format)()
2840
        target_repository_format = unordered_format.repository_format
2841
        # Cross check
2842
        self.assertEqual(order, target_repository_format._fetch_order)
2843
        trunk, stacked = self.prepare_stacked_remote_branch()
2844
        source = stacked.repository._get_source(target_repository_format)
2845
        tip = stacked.last_revision()
2846
        revs = stacked.repository.get_ancestry(tip)
2847
        search = graph.PendingAncestryResult([tip], stacked.repository)
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2848
        self.reset_smart_call_log()
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2849
        stream = source.get_stream(search)
2850
        if None in revs:
2851
            revs.remove(None)
2852
        # We trust that if a revision is in the stream the rest of the new
2853
        # content for it is too, as per our main fetch tests; here we are
2854
        # checking that the revisions are actually included at all, and their
2855
        # order.
2856
        return self.fetch_stream_to_rev_order(stream), revs
2857
2858
    def test_stacked_get_stream_unordered(self):
2859
        # Repository._get_source.get_stream() from a stacked repository with
2860
        # unordered yields the full data from both stacked and stacked upon
2861
        # sources.
2862
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered')
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2863
        self.assertEqual(set(expected_revs), set(rev_ord))
2864
        # Getting unordered results should have made a streaming data request
2865
        # from the server, then one from the backing branch.
2866
        self.assertLength(2, self.hpss_calls)
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2867
2868
    def test_stacked_get_stream_topological(self):
2869
        # Repository._get_source.get_stream() from a stacked repository with
2870
        # topological sorting yields the full data from both stacked and
2871
        # stacked upon sources in topological order.
2872
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2873
        self.assertEqual(expected_revs, rev_ord)
2874
        # Getting topological sort requires VFS calls still
4190.1.6 by Robert Collins
Missed some unit tests.
2875
        self.assertLength(12, self.hpss_calls)
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2876
2877
    def test_stacked_get_stream_groupcompress(self):
2878
        # Repository._get_source.get_stream() from a stacked repository with
2879
        # groupcompress sorting yields the full data from both stacked and
2880
        # stacked upon sources in groupcompress order.
2881
        raise tests.TestSkipped('No groupcompress ordered format available')
2882
        rev_ord, expected_revs = self.get_ordered_revs('dev5', 'groupcompress')
4152.1.2 by Robert Collins
Add streaming from a stacked branch when the sort order is compatible with doing so.
2883
        self.assertEqual(expected_revs, reversed(rev_ord))
2884
        # Getting unordered results should have made a streaming data request
2885
        # from the backing branch, and one from the stacked on branch.
2886
        self.assertLength(2, self.hpss_calls)
4152.1.1 by Robert Collins
Add specific tests for fetch streaming in the bzr protocol client.
2887
4332.2.1 by Robert Collins
Fix bug 360791 by not raising an error when a smart server is asked for more content than it has locally; the client is assumed to be monitoring what it gets.
2888
    def test_stacked_pull_more_than_stacking_has_bug_360791(self):
2889
        # When pulling some fixed amount of content that is more than the
2890
        # source has (because some is coming from a fallback branch, no error
2891
        # should be received. This was reported as bug 360791.
2892
        # Need three branches: a trunk, a stacked branch, and a preexisting
2893
        # branch pulling content from stacked and trunk.
2894
        self.setup_smart_server_with_call_log()
2895
        trunk = self.make_branch_and_tree('trunk', format="1.9-rich-root")
2896
        r1 = trunk.commit('start')
2897
        stacked_branch = trunk.branch.create_clone_on_transport(
2898
            self.get_transport('stacked'), stacked_on=trunk.branch.base)
2899
        local = self.make_branch('local', format='1.9-rich-root')
2900
        local.repository.fetch(stacked_branch.repository,
2901
            stacked_branch.last_revision())
2902
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.
2903
2904
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
2905
2906
    def setUp(self):
2907
        super(TestRemoteBranchEffort, self).setUp()
2908
        # Create a smart server that publishes whatever the backing VFS server
2909
        # does.
2910
        self.smart_server = server.SmartTCPServer_for_testing()
2911
        self.smart_server.setUp(self.get_server())
2912
        self.addCleanup(self.smart_server.tearDown)
2913
        # Log all HPSS calls into self.hpss_calls.
2914
        _SmartClient.hooks.install_named_hook(
2915
            'call', self.capture_hpss_call, None)
2916
        self.hpss_calls = []
2917
2918
    def capture_hpss_call(self, params):
2919
        self.hpss_calls.append(params.method)
2920
2921
    def test_copy_content_into_avoids_revision_history(self):
2922
        local = self.make_branch('local')
2923
        remote_backing_tree = self.make_branch_and_tree('remote')
2924
        remote_backing_tree.commit("Commit.")
2925
        remote_branch_url = self.smart_server.get_url() + 'remote'
2926
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
2927
        local.repository.fetch(remote_branch.repository)
2928
        self.hpss_calls = []
2929
        remote_branch.copy_content_into(local)
3834.3.3 by John Arbash Meinel
Merge bzr.dev, resolve conflict in tests.
2930
        self.assertFalse('Branch.revision_history' in self.hpss_calls)