/brz/remove-bazaar

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