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