/brz/remove-bazaar

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