/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
1
# Copyright (C) 2006, 2007 Canonical Ltd
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
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
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
17
"""Tests for the smart wire/domain protocol.
18
19
This module contains tests for the domain-level smart requests and responses,
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
20
such as the 'Branch.lock_write' request. Many of these use specific disk
21
formats to exercise calls that only make sense for formats with specific
22
properties.
2748.4.1 by Andrew Bennetts
Implement a ChunkedBodyDecoder.
23
24
Tests for low-level protocol encoding are found in test_smart_transport.
25
"""
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
26
3211.5.2 by Robert Collins
Change RemoteRepository.get_parent_map to use bz2 not gzip for compression.
27
import bz2
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
28
from StringIO import StringIO
29
import tempfile
30
import tarfile
31
2535.3.31 by Andrew Bennetts
Fix imports broken by reverting the container-format merge. I didn't notice them earlier because of .pyc files :(
32
from bzrlib import bzrdir, errors, pack, smart, tests
2535.4.5 by Andrew Bennetts
Merge latest chunking protocol, including support for errors, fixing a test failure.
33
from bzrlib.smart.request import (
34
    FailedSmartServerResponse,
35
    SmartServerResponse,
36
    SuccessfulSmartServerResponse,
37
    )
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
38
import bzrlib.smart.bzrdir
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
39
import bzrlib.smart.branch
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
40
import bzrlib.smart.repository
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
41
from bzrlib.tests import (
42
    iter_suite_tests,
43
    split_suite_by_re,
44
    TestScenarioApplier,
45
    )
2535.3.15 by Andrew Bennetts
Add KnitVersionedFile.get_stream_as_bytes, start smart implementation of RemoteRepository.get_data_stream.
46
from bzrlib.util import bencode
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
47
48
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
49
def load_tests(standard_tests, module, loader):
50
    """Multiply tests version and protocol consistency."""
51
    # FindRepository tests.
52
    bzrdir_mod = bzrlib.smart.bzrdir
53
    applier = TestScenarioApplier()
54
    applier.scenarios = [
55
        ("find_repository", {
56
            "_request_class":bzrdir_mod.SmartServerRequestFindRepositoryV1}),
57
        ("find_repositoryV2", {
58
            "_request_class":bzrdir_mod.SmartServerRequestFindRepositoryV2}),
59
        ]
60
    to_adapt, result = split_suite_by_re(standard_tests,
61
        "TestSmartServerRequestFindRepository")
62
    v2_only, v1_and_2 = split_suite_by_re(to_adapt,
63
        "_v2")
64
    for test in iter_suite_tests(v1_and_2):
65
        result.addTests(applier.adapt(test))
66
    del applier.scenarios[0]
67
    for test in iter_suite_tests(v2_only):
68
        result.addTests(applier.adapt(test))
69
    return result
70
71
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
72
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
73
74
    def setUp(self):
75
        super(TestCaseWithSmartMedium, self).setUp()
76
        # We're allowed to set  the transport class here, so that we don't use
77
        # the default or a parameterized class, but rather use the
78
        # TestCaseWithTransport infrastructure to set up a smart server and
79
        # transport.
80
        self.transport_server = smart.server.SmartTCPServer_for_testing
81
82
    def get_smart_medium(self):
83
        """Get a smart medium to use in tests."""
84
        return self.get_transport().get_smart_medium()
85
86
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
87
class TestSmartServerResponse(tests.TestCase):
88
89
    def test__eq__(self):
90
        self.assertEqual(SmartServerResponse(('ok', )),
91
            SmartServerResponse(('ok', )))
92
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
93
            SmartServerResponse(('ok', ), 'body'))
94
        self.assertNotEqual(SmartServerResponse(('ok', )),
95
            SmartServerResponse(('notok', )))
96
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
97
            SmartServerResponse(('ok', )))
2018.5.41 by Robert Collins
Fix SmartServerResponse.__eq__ to handle None.
98
        self.assertNotEqual(None,
99
            SmartServerResponse(('ok', )))
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
100
101
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
102
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
103
    """Tests for BzrDir.find_repository."""
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
104
105
    def test_no_repository(self):
106
        """When there is no repository to be found, ('norepository', ) is returned."""
107
        backing = self.get_transport()
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
108
        request = self._request_class(backing)
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
109
        self.make_bzrdir('.')
110
        self.assertEqual(SmartServerResponse(('norepository', )),
111
            request.execute(backing.local_abspath('')))
112
113
    def test_nonshared_repository(self):
114
        # nonshared repositorys only allow 'find' to return a handle when the 
115
        # path the repository is being searched on is the same as that that 
116
        # the repository is at.
117
        backing = self.get_transport()
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
118
        request = self._request_class(backing)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
119
        result = self._make_repository_and_result()
120
        self.assertEqual(result, request.execute(backing.local_abspath('')))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
121
        self.make_bzrdir('subdir')
122
        self.assertEqual(SmartServerResponse(('norepository', )),
123
            request.execute(backing.local_abspath('subdir')))
124
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
125
    def _make_repository_and_result(self, shared=False, format=None):
126
        """Convenience function to setup a repository.
127
128
        :result: The SmartServerResponse to expect when opening it.
129
        """
130
        repo = self.make_repository('.', shared=shared, format=format)
131
        if repo.supports_rich_root():
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
132
            rich_root = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
133
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
134
            rich_root = 'no'
2018.5.138 by Robert Collins
Merge bzr.dev.
135
        if repo._format.supports_tree_reference:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
136
            subtrees = 'yes'
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
137
        else:
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
138
            subtrees = 'no'
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
139
        if (smart.bzrdir.SmartServerRequestFindRepositoryV2 ==
140
            self._request_class):
141
            # All tests so far are on formats, and for non-external
142
            # repositories.
143
            return SuccessfulSmartServerResponse(
144
                ('ok', '', rich_root, subtrees, 'no'))
145
        else:
146
            return SuccessfulSmartServerResponse(('ok', '', rich_root, subtrees))
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
147
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
148
    def test_shared_repository(self):
149
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
150
        backing = self.get_transport()
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
151
        request = self._request_class(backing)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
152
        result = self._make_repository_and_result(shared=True)
153
        self.assertEqual(result, request.execute(backing.local_abspath('')))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
154
        self.make_bzrdir('subdir')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
155
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
156
        self.assertEqual(result2,
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
157
            request.execute(backing.local_abspath('subdir')))
158
        self.make_bzrdir('subdir/deeper')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
159
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
160
        self.assertEqual(result3,
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
161
            request.execute(backing.local_abspath('subdir/deeper')))
162
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
163
    def test_rich_root_and_subtree_encoding(self):
164
        """Test for the format attributes for rich root and subtree support."""
165
        backing = self.get_transport()
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
166
        request = self._request_class(backing)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
167
        result = self._make_repository_and_result(format='dirstate-with-subtree')
168
        # check the test will be valid
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
169
        self.assertEqual('yes', result.args[2])
170
        self.assertEqual('yes', result.args[3])
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
171
        self.assertEqual(result, request.execute(backing.local_abspath('')))
172
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
173
    def test_supports_external_lookups_no_v2(self):
174
        """Test for the supports_external_lookups attribute."""
175
        backing = self.get_transport()
176
        request = self._request_class(backing)
177
        result = self._make_repository_and_result(format='dirstate-with-subtree')
178
        # check the test will be valid
179
        self.assertEqual('no', result.args[4])
180
        self.assertEqual(result, request.execute(backing.local_abspath('')))
181
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
182
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
183
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
184
185
    def test_empty_dir(self):
186
        """Initializing an empty dir should succeed and do it."""
187
        backing = self.get_transport()
188
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
189
        self.assertEqual(SmartServerResponse(('ok', )),
190
            request.execute(backing.local_abspath('.')))
191
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
192
        # no branch, tree or repository is expected with the current 
193
        # default formart.
194
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
195
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
196
        self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
197
198
    def test_missing_dir(self):
199
        """Initializing a missing directory should fail like the bzrdir api."""
200
        backing = self.get_transport()
201
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
202
        self.assertRaises(errors.NoSuchFile,
203
            request.execute, backing.local_abspath('subdir'))
204
205
    def test_initialized_dir(self):
206
        """Initializing an extant bzrdir should fail like the bzrdir api."""
207
        backing = self.get_transport()
208
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
209
        self.make_bzrdir('subdir')
210
        self.assertRaises(errors.FileExists,
211
            request.execute, backing.local_abspath('subdir'))
212
213
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
214
class TestSmartServerRequestOpenBranch(tests.TestCaseWithTransport):
215
216
    def test_no_branch(self):
217
        """When there is no branch, ('nobranch', ) is returned."""
218
        backing = self.get_transport()
219
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
220
        self.make_bzrdir('.')
221
        self.assertEqual(SmartServerResponse(('nobranch', )),
222
            request.execute(backing.local_abspath('')))
223
224
    def test_branch(self):
225
        """When there is a branch, 'ok' is returned."""
226
        backing = self.get_transport()
227
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
228
        self.make_branch('.')
229
        self.assertEqual(SmartServerResponse(('ok', '')),
230
            request.execute(backing.local_abspath('')))
231
232
    def test_branch_reference(self):
233
        """When there is a branch reference, the reference URL is returned."""
234
        backing = self.get_transport()
235
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
236
        branch = self.make_branch('branch')
237
        checkout = branch.create_checkout('reference',lightweight=True)
238
        # TODO: once we have an API to probe for references of any sort, we
239
        # can use it here.
240
        reference_url = backing.abspath('branch') + '/'
241
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
242
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
243
            request.execute(backing.local_abspath('reference')))
244
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
245
246
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithTransport):
247
248
    def test_empty(self):
249
        """For an empty branch, the body is empty."""
250
        backing = self.get_transport()
251
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
252
        self.make_branch('.')
253
        self.assertEqual(SmartServerResponse(('ok', ), ''),
254
            request.execute(backing.local_abspath('')))
255
256
    def test_not_empty(self):
257
        """For a non-empty branch, the body is empty."""
258
        backing = self.get_transport()
259
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
260
        tree = self.make_branch_and_memory_tree('.')
261
        tree.lock_write()
262
        tree.add('')
263
        r1 = tree.commit('1st commit')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
264
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
265
        tree.unlock()
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
266
        self.assertEqual(
267
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
268
            request.execute(backing.local_abspath('')))
269
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
270
271
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
272
273
    def test_no_branch(self):
274
        """When there is a bzrdir and no branch, NotBranchError is raised."""
275
        backing = self.get_transport()
276
        request = smart.branch.SmartServerBranchRequest(backing)
277
        self.make_bzrdir('.')
278
        self.assertRaises(errors.NotBranchError,
279
            request.execute, backing.local_abspath(''))
280
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
281
    def test_branch_reference(self):
282
        """When there is a branch reference, NotBranchError is raised."""
283
        backing = self.get_transport()
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
284
        request = smart.branch.SmartServerBranchRequest(backing)
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
285
        branch = self.make_branch('branch')
286
        checkout = branch.create_checkout('reference',lightweight=True)
287
        self.assertRaises(errors.NotBranchError,
288
            request.execute, backing.local_abspath('checkout'))
289
290
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
291
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
292
293
    def test_empty(self):
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
294
        """For an empty branch, the result is ('ok', '0', 'null:')."""
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
295
        backing = self.get_transport()
296
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
297
        self.make_branch('.')
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
298
        self.assertEqual(SmartServerResponse(('ok', '0', 'null:')),
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
299
            request.execute(backing.local_abspath('')))
300
301
    def test_not_empty(self):
302
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
303
        backing = self.get_transport()
304
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
305
        tree = self.make_branch_and_memory_tree('.')
306
        tree.lock_write()
307
        tree.add('')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
308
        rev_id_utf8 = u'\xc8'.encode('utf-8')
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
309
        r1 = tree.commit('1st commit')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
310
        r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
311
        tree.unlock()
312
        self.assertEqual(
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
313
            SmartServerResponse(('ok', '2', rev_id_utf8)),
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
314
            request.execute(backing.local_abspath('')))
315
316
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
317
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithTransport):
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
318
319
    def test_default(self):
320
        """With no file, we get empty content."""
321
        backing = self.get_transport()
322
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
323
        branch = self.make_branch('.')
324
        # there should be no file by default
325
        content = ''
326
        self.assertEqual(SmartServerResponse(('ok', ), content),
327
            request.execute(backing.local_abspath('')))
328
329
    def test_with_content(self):
330
        # SmartServerBranchGetConfigFile should return the content from
331
        # branch.control_files.get('branch.conf') for now - in the future it may
332
        # perform more complex processing. 
333
        backing = self.get_transport()
334
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
335
        branch = self.make_branch('.')
336
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
337
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
338
            request.execute(backing.local_abspath('')))
339
340
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
341
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
342
343
    def test_empty(self):
344
        backing = self.get_transport()
345
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
346
        b = self.make_branch('.')
2018.5.144 by Andrew Bennetts
Fix four tests I broke with the Branch.lock_write changes.
347
        branch_token = b.lock_write()
348
        repo_token = b.repository.lock_write()
349
        b.repository.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
350
        try:
351
            self.assertEqual(SmartServerResponse(('ok',)),
352
                request.execute(
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
353
                    backing.local_abspath(''), branch_token, repo_token,
354
                    'null:'))
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
355
        finally:
356
            b.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
357
358
    def test_not_present_revision_id(self):
359
        backing = self.get_transport()
360
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
361
        b = self.make_branch('.')
2018.5.144 by Andrew Bennetts
Fix four tests I broke with the Branch.lock_write changes.
362
        branch_token = b.lock_write()
363
        repo_token = b.repository.lock_write()
364
        b.repository.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
365
        try:
366
            revision_id = 'non-existent revision'
367
            self.assertEqual(
368
                SmartServerResponse(('NoSuchRevision', revision_id)),
369
                request.execute(
370
                    backing.local_abspath(''), branch_token, repo_token,
371
                    revision_id))
372
        finally:
373
            b.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
374
375
    def test_revision_id_present(self):
376
        backing = self.get_transport()
377
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
378
        tree = self.make_branch_and_memory_tree('.')
379
        tree.lock_write()
380
        tree.add('')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
381
        rev_id_utf8 = u'\xc8'.encode('utf-8')
382
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
383
        r2 = tree.commit('2nd commit')
384
        tree.unlock()
2018.5.144 by Andrew Bennetts
Fix four tests I broke with the Branch.lock_write changes.
385
        branch_token = tree.branch.lock_write()
386
        repo_token = tree.branch.repository.lock_write()
387
        tree.branch.repository.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
388
        try:
389
            self.assertEqual(
390
                SmartServerResponse(('ok',)),
391
                request.execute(
392
                    backing.local_abspath(''), branch_token, repo_token,
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
393
                    rev_id_utf8))
394
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
395
        finally:
396
            tree.branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
397
398
    def test_revision_id_present2(self):
399
        backing = self.get_transport()
400
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
401
        tree = self.make_branch_and_memory_tree('.')
402
        tree.lock_write()
403
        tree.add('')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
404
        rev_id_utf8 = u'\xc8'.encode('utf-8')
405
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
406
        r2 = tree.commit('2nd commit')
407
        tree.unlock()
408
        tree.branch.set_revision_history([])
2018.5.144 by Andrew Bennetts
Fix four tests I broke with the Branch.lock_write changes.
409
        branch_token = tree.branch.lock_write()
410
        repo_token = tree.branch.repository.lock_write()
411
        tree.branch.repository.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
412
        try:
413
            self.assertEqual(
414
                SmartServerResponse(('ok',)),
415
                request.execute(
416
                    backing.local_abspath(''), branch_token, repo_token,
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
417
                    rev_id_utf8))
418
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
419
        finally:
420
            tree.branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
421
422
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
423
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
424
425
    def setUp(self):
426
        tests.TestCaseWithTransport.setUp(self)
427
428
    def test_lock_write_on_unlocked_branch(self):
429
        backing = self.get_transport()
430
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
431
        branch = self.make_branch('.', format='knit')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
432
        repository = branch.repository
433
        response = request.execute(backing.local_abspath(''))
434
        branch_nonce = branch.control_files._lock.peek().get('nonce')
435
        repository_nonce = repository.control_files._lock.peek().get('nonce')
436
        self.assertEqual(
437
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
438
            response)
439
        # The branch (and associated repository) is now locked.  Verify that
440
        # with a new branch object.
441
        new_branch = repository.bzrdir.open_branch()
442
        self.assertRaises(errors.LockContention, new_branch.lock_write)
443
444
    def test_lock_write_on_locked_branch(self):
445
        backing = self.get_transport()
446
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
447
        branch = self.make_branch('.')
448
        branch.lock_write()
449
        branch.leave_lock_in_place()
450
        branch.unlock()
451
        response = request.execute(backing.local_abspath(''))
452
        self.assertEqual(
453
            SmartServerResponse(('LockContention',)), response)
454
455
    def test_lock_write_with_tokens_on_locked_branch(self):
456
        backing = self.get_transport()
457
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
458
        branch = self.make_branch('.', format='knit')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
459
        branch_token = branch.lock_write()
460
        repo_token = branch.repository.lock_write()
461
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
462
        branch.leave_lock_in_place()
463
        branch.repository.leave_lock_in_place()
464
        branch.unlock()
465
        response = request.execute(backing.local_abspath(''),
466
                                   branch_token, repo_token)
467
        self.assertEqual(
468
            SmartServerResponse(('ok', branch_token, repo_token)), response)
469
470
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
471
        backing = self.get_transport()
472
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
473
        branch = self.make_branch('.', format='knit')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
474
        branch_token = branch.lock_write()
475
        repo_token = branch.repository.lock_write()
476
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
477
        branch.leave_lock_in_place()
478
        branch.repository.leave_lock_in_place()
479
        branch.unlock()
480
        response = request.execute(backing.local_abspath(''),
481
                                   branch_token+'xxx', repo_token)
482
        self.assertEqual(
483
            SmartServerResponse(('TokenMismatch',)), response)
484
485
    def test_lock_write_on_locked_repo(self):
486
        backing = self.get_transport()
487
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
488
        branch = self.make_branch('.', format='knit')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
489
        branch.repository.lock_write()
490
        branch.repository.leave_lock_in_place()
491
        branch.repository.unlock()
492
        response = request.execute(backing.local_abspath(''))
493
        self.assertEqual(
494
            SmartServerResponse(('LockContention',)), response)
495
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.
496
    def test_lock_write_on_readonly_transport(self):
497
        backing = self.get_readonly_transport()
498
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
499
        branch = self.make_branch('.')
500
        response = request.execute('')
2872.5.3 by Martin Pool
Pass back LockFailed from smart server lock methods
501
        error_name, lock_str, why_str = response.args
502
        self.assertFalse(response.is_successful())
503
        self.assertEqual('LockFailed', error_name)
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.
504
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
505
506
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
507
508
    def setUp(self):
509
        tests.TestCaseWithTransport.setUp(self)
510
511
    def test_unlock_on_locked_branch_and_repo(self):
512
        backing = self.get_transport()
513
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
514
        branch = self.make_branch('.', format='knit')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
515
        # Lock the branch
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
516
        branch_token = branch.lock_write()
517
        repo_token = branch.repository.lock_write()
518
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
519
        # Unlock the branch (and repo) object, leaving the physical locks
520
        # in place.
521
        branch.leave_lock_in_place()
522
        branch.repository.leave_lock_in_place()
523
        branch.unlock()
524
        response = request.execute(backing.local_abspath(''),
525
                                   branch_token, repo_token)
526
        self.assertEqual(
527
            SmartServerResponse(('ok',)), response)
528
        # The branch is now unlocked.  Verify that with a new branch
529
        # object.
530
        new_branch = branch.bzrdir.open_branch()
531
        new_branch.lock_write()
532
        new_branch.unlock()
533
534
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
535
        backing = self.get_transport()
536
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
537
        branch = self.make_branch('.', format='knit')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
538
        response = request.execute(
539
            backing.local_abspath(''), 'branch token', 'repo token')
540
        self.assertEqual(
541
            SmartServerResponse(('TokenMismatch',)), response)
542
543
    def test_unlock_on_unlocked_branch_locked_repo(self):
544
        backing = self.get_transport()
545
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
546
        branch = self.make_branch('.', format='knit')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
547
        # Lock the repository.
548
        repo_token = branch.repository.lock_write()
549
        branch.repository.leave_lock_in_place()
550
        branch.repository.unlock()
551
        # Issue branch lock_write request on the unlocked branch (with locked
552
        # repo).
553
        response = request.execute(
554
            backing.local_abspath(''), 'branch token', repo_token)
555
        self.assertEqual(
556
            SmartServerResponse(('TokenMismatch',)), response)
557
558
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
559
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
560
561
    def test_no_repository(self):
562
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
563
        # we test this using a shared repository above the named path,
564
        # thus checking the right search logic is used - that is, that
565
        # its the exact path being looked at and the server is not
566
        # searching.
567
        backing = self.get_transport()
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
568
        request = smart.repository.SmartServerRepositoryRequest(backing)
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
569
        self.make_repository('.', shared=True)
570
        self.make_bzrdir('subdir')
571
        self.assertRaises(errors.NoRepositoryPresent,
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
572
            request.execute, backing.local_abspath('subdir'))
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
573
574
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.
575
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithTransport):
576
3211.5.3 by Robert Collins
Adjust size of batch and change gzip comments to bzip2.
577
    def test_trivial_bzipped(self):
578
        # This tests that the wire encoding is actually bzipped
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.
579
        backing = self.get_transport()
580
        request = smart.repository.SmartServerRepositoryGetParentMap(backing)
581
        tree = self.make_branch_and_memory_tree('.')
582
583
        self.assertEqual(None,
584
            request.execute(backing.local_abspath(''), 'missing-id'))
3211.5.3 by Robert Collins
Adjust size of batch and change gzip comments to bzip2.
585
        # Note that it returns a body (of '' bzipped).
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.
586
        self.assertEqual(
3211.5.2 by Robert Collins
Change RemoteRepository.get_parent_map to use bz2 not gzip for compression.
587
            SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
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.
588
            request.do_body('\n\n0\n'))
589
590
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
591
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
592
593
    def test_none_argument(self):
594
        backing = self.get_transport()
595
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
596
        tree = self.make_branch_and_memory_tree('.')
597
        tree.lock_write()
598
        tree.add('')
599
        r1 = tree.commit('1st commit')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
600
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
601
        tree.unlock()
602
603
        # the lines of revision_id->revision_parent_list has no guaranteed
604
        # order coming out of a dict, so sort both our test and response
605
        lines = sorted([' '.join([r2, r1]), r1])
606
        response = request.execute(backing.local_abspath(''), '')
607
        response.body = '\n'.join(sorted(response.body.split('\n')))
608
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
609
        self.assertEqual(
610
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
611
612
    def test_specific_revision_argument(self):
613
        backing = self.get_transport()
614
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
615
        tree = self.make_branch_and_memory_tree('.')
616
        tree.lock_write()
617
        tree.add('')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
618
        rev_id_utf8 = u'\xc9'.encode('utf-8')
619
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
620
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
621
        tree.unlock()
622
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
623
        self.assertEqual(SmartServerResponse(('ok', ), rev_id_utf8),
624
            request.execute(backing.local_abspath(''), rev_id_utf8))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
625
    
626
    def test_no_such_revision(self):
627
        backing = self.get_transport()
628
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
629
        tree = self.make_branch_and_memory_tree('.')
630
        tree.lock_write()
631
        tree.add('')
632
        r1 = tree.commit('1st commit')
633
        tree.unlock()
634
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
635
        # Note that it still returns body (of zero bytes).
636
        self.assertEqual(
637
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
638
            request.execute(backing.local_abspath(''), 'missingrevision'))
639
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
640
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
641
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
642
643
    def test_missing_revision(self):
644
        """For a missing revision, ('no', ) is returned."""
645
        backing = self.get_transport()
646
        request = smart.repository.SmartServerRequestHasRevision(backing)
647
        self.make_repository('.')
648
        self.assertEqual(SmartServerResponse(('no', )),
649
            request.execute(backing.local_abspath(''), 'revid'))
650
651
    def test_present_revision(self):
2018.5.158 by Andrew Bennetts
Return 'yes'/'no' rather than 'ok'/'no' from the Repository.has_revision smart command.
652
        """For a present revision, ('yes', ) is returned."""
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
653
        backing = self.get_transport()
654
        request = smart.repository.SmartServerRequestHasRevision(backing)
655
        tree = self.make_branch_and_memory_tree('.')
656
        tree.lock_write()
657
        tree.add('')
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
658
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
659
        r1 = tree.commit('a commit', rev_id=rev_id_utf8)
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
660
        tree.unlock()
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
661
        self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
2018.5.158 by Andrew Bennetts
Return 'yes'/'no' rather than 'ok'/'no' from the Repository.has_revision smart command.
662
        self.assertEqual(SmartServerResponse(('yes', )),
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
663
            request.execute(backing.local_abspath(''), rev_id_utf8))
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
664
665
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
666
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
667
668
    def test_empty_revid(self):
669
        """With an empty revid, we get only size an number and revisions"""
670
        backing = self.get_transport()
671
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
672
        repository = self.make_repository('.')
673
        stats = repository.gather_stats()
674
        size = stats['size']
675
        expected_body = 'revisions: 0\nsize: %d\n' % size
676
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
677
                         request.execute(backing.local_abspath(''), '', 'no'))
678
679
    def test_revid_with_committers(self):
680
        """For a revid we get more infos."""
681
        backing = self.get_transport()
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
682
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
683
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
684
        tree = self.make_branch_and_memory_tree('.')
685
        tree.lock_write()
686
        tree.add('')
687
        # Let's build a predictable result
688
        tree.commit('a commit', timestamp=123456.2, timezone=3600)
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
689
        tree.commit('a commit', timestamp=654321.4, timezone=0,
690
                    rev_id=rev_id_utf8)
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
691
        tree.unlock()
692
693
        stats = tree.branch.repository.gather_stats()
694
        size = stats['size']
695
        expected_body = ('firstrev: 123456.200 3600\n'
696
                         'latestrev: 654321.400 0\n'
697
                         'revisions: 2\n'
698
                         'size: %d\n' % size)
699
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
700
                         request.execute(backing.local_abspath(''),
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
701
                                         rev_id_utf8, 'no'))
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
702
703
    def test_not_empty_repository_with_committers(self):
704
        """For a revid and requesting committers we get the whole thing."""
705
        backing = self.get_transport()
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
706
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
707
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
708
        tree = self.make_branch_and_memory_tree('.')
709
        tree.lock_write()
710
        tree.add('')
711
        # Let's build a predictable result
712
        tree.commit('a commit', timestamp=123456.2, timezone=3600,
713
                    committer='foo')
714
        tree.commit('a commit', timestamp=654321.4, timezone=0,
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
715
                    committer='bar', rev_id=rev_id_utf8)
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
716
        tree.unlock()
717
        stats = tree.branch.repository.gather_stats()
718
719
        size = stats['size']
720
        expected_body = ('committers: 2\n'
721
                         'firstrev: 123456.200 3600\n'
722
                         'latestrev: 654321.400 0\n'
723
                         'revisions: 2\n'
724
                         'size: %d\n' % size)
725
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
726
                         request.execute(backing.local_abspath(''),
2018.5.148 by Andrew Bennetts
Fix all the DeprecationWarnings in test_smart caused by unicode revision IDs.
727
                                         rev_id_utf8, 'yes'))
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
728
729
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
730
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
731
732
    def test_is_shared(self):
733
        """For a shared repository, ('yes', ) is returned."""
734
        backing = self.get_transport()
735
        request = smart.repository.SmartServerRepositoryIsShared(backing)
736
        self.make_repository('.', shared=True)
737
        self.assertEqual(SmartServerResponse(('yes', )),
738
            request.execute(backing.local_abspath(''), ))
739
740
    def test_is_not_shared(self):
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
741
        """For a shared repository, ('no', ) is returned."""
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
742
        backing = self.get_transport()
743
        request = smart.repository.SmartServerRepositoryIsShared(backing)
744
        self.make_repository('.', shared=False)
745
        self.assertEqual(SmartServerResponse(('no', )),
746
            request.execute(backing.local_abspath(''), ))
747
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
748
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
749
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
750
751
    def setUp(self):
752
        tests.TestCaseWithTransport.setUp(self)
753
754
    def test_lock_write_on_unlocked_repo(self):
755
        backing = self.get_transport()
756
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
757
        repository = self.make_repository('.', format='knit')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
758
        response = request.execute(backing.local_abspath(''))
759
        nonce = repository.control_files._lock.peek().get('nonce')
760
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
761
        # The repository is now locked.  Verify that with a new repository
762
        # object.
763
        new_repo = repository.bzrdir.open_repository()
764
        self.assertRaises(errors.LockContention, new_repo.lock_write)
765
766
    def test_lock_write_on_locked_repo(self):
767
        backing = self.get_transport()
768
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
769
        repository = self.make_repository('.', format='knit')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
770
        repository.lock_write()
771
        repository.leave_lock_in_place()
772
        repository.unlock()
773
        response = request.execute(backing.local_abspath(''))
774
        self.assertEqual(
775
            SmartServerResponse(('LockContention',)), response)
776
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.
777
    def test_lock_write_on_readonly_transport(self):
778
        backing = self.get_readonly_transport()
779
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
780
        repository = self.make_repository('.', format='knit')
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.
781
        response = request.execute('')
2872.5.3 by Martin Pool
Pass back LockFailed from smart server lock methods
782
        self.assertFalse(response.is_successful())
783
        self.assertEqual('LockFailed', response.args[0])
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.
784
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
785
786
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
787
788
    def setUp(self):
789
        tests.TestCaseWithTransport.setUp(self)
790
791
    def test_unlock_on_locked_repo(self):
792
        backing = self.get_transport()
793
        request = smart.repository.SmartServerRepositoryUnlock(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
794
        repository = self.make_repository('.', format='knit')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
795
        token = repository.lock_write()
796
        repository.leave_lock_in_place()
797
        repository.unlock()
798
        response = request.execute(backing.local_abspath(''), token)
799
        self.assertEqual(
800
            SmartServerResponse(('ok',)), response)
801
        # The repository is now unlocked.  Verify that with a new repository
802
        # object.
803
        new_repo = repository.bzrdir.open_repository()
804
        new_repo.lock_write()
805
        new_repo.unlock()
806
807
    def test_unlock_on_unlocked_repo(self):
808
        backing = self.get_transport()
809
        request = smart.repository.SmartServerRepositoryUnlock(backing)
3015.2.12 by Robert Collins
Make test_smart use specific formats as needed to exercise locked and unlocked repositories.
810
        repository = self.make_repository('.', format='knit')
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
811
        response = request.execute(backing.local_abspath(''), 'some token')
812
        self.assertEqual(
813
            SmartServerResponse(('TokenMismatch',)), response)
814
815
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
816
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
817
818
    def test_repository_tarball(self):
819
        backing = self.get_transport()
820
        request = smart.repository.SmartServerRepositoryTarball(backing)
821
        repository = self.make_repository('.')
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
822
        # make some extraneous junk in the repository directory which should
823
        # not be copied
824
        self.build_tree(['.bzr/repository/extra-junk'])
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
825
        response = request.execute(backing.local_abspath(''), 'bz2')
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
826
        self.assertEqual(('ok',), response.args)
827
        # body should be a tbz2
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
828
        body_file = StringIO(response.body)
829
        body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
2018.18.25 by Martin Pool
Repository.tarball fixes for python2.4
830
            mode='r|bz2')
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
831
        # let's make sure there are some key repository components inside it.
832
        # the tarfile returns directories with trailing slashes...
833
        names = set([n.rstrip('/') for n in body_tar.getnames()])
2018.18.11 by Martin Pool
merge hpss changes
834
        self.assertTrue('.bzr/repository/lock' in names)
835
        self.assertTrue('.bzr/repository/format' in names)
836
        self.assertTrue('.bzr/repository/extra-junk' not in names,
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
837
            "extraneous file present in tar file")
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
838
839
2535.3.49 by Andrew Bennetts
Rename 'Repository.fetch_revisions' smart request to 'Repository.stream_knit_data_for_revisions'.
840
class TestSmartServerRepositoryStreamKnitData(tests.TestCaseWithTransport):
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
841
842
    def test_fetch_revisions(self):
843
        backing = self.get_transport()
2535.3.49 by Andrew Bennetts
Rename 'Repository.fetch_revisions' smart request to 'Repository.stream_knit_data_for_revisions'.
844
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
845
        tree = self.make_branch_and_memory_tree('.')
846
        tree.lock_write()
847
        tree.add('')
848
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
849
        rev_id2_utf8 = u'\xc9'.encode('utf-8')
850
        r1 = tree.commit('1st commit', rev_id=rev_id1_utf8)
851
        r1 = tree.commit('2nd commit', rev_id=rev_id2_utf8)
852
        tree.unlock()
853
854
        response = request.execute(backing.local_abspath(''), rev_id2_utf8)
855
        self.assertEqual(('ok',), response.args)
856
        from cStringIO import StringIO
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
857
        unpacker = pack.ContainerReader(StringIO(response.body))
858
        names = []
859
        for [name], read_bytes in unpacker.iter_records():
860
            names.append(name)
861
            bytes = read_bytes(None)
862
            # The bytes should be a valid bencoded string.
863
            bencode.bdecode(bytes)
864
            # XXX: assert that the bencoded knit records have the right
865
            # contents?
866
        
867
    def test_no_such_revision_error(self):
868
        backing = self.get_transport()
869
        request = smart.repository.SmartServerRepositoryStreamKnitDataForRevisions(backing)
870
        repo = self.make_repository('.')
871
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
872
        response = request.execute(backing.local_abspath(''), rev_id1_utf8)
873
        self.assertEqual(
874
            SmartServerResponse(('NoSuchRevision', rev_id1_utf8)),
875
            response)
876
877
878
class TestSmartServerRepositoryStreamRevisionsChunked(tests.TestCaseWithTransport):
879
880
    def test_fetch_revisions(self):
881
        backing = self.get_transport()
882
        request = smart.repository.SmartServerRepositoryStreamRevisionsChunked(
883
            backing)
884
        tree = self.make_branch_and_memory_tree('.')
885
        tree.lock_write()
886
        tree.add('')
887
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
888
        rev_id2_utf8 = u'\xc9'.encode('utf-8')
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.
889
        tree.commit('1st commit', rev_id=rev_id1_utf8)
890
        tree.commit('2nd commit', rev_id=rev_id2_utf8)
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
891
        tree.unlock()
892
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.
893
        response = request.execute(backing.local_abspath(''))
894
        self.assertEqual(None, response)
895
        response = request.do_body("%s\n%s\n1" % (rev_id2_utf8, rev_id1_utf8))
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
896
        self.assertEqual(('ok',), response.args)
897
        from cStringIO import StringIO
2535.4.22 by Andrew Bennetts
Merge from streamable-containers.
898
        parser = pack.ContainerPushParser()
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
899
        names = []
2535.4.22 by Andrew Bennetts
Merge from streamable-containers.
900
        for stream_bytes in response.body_stream:
901
            parser.accept_bytes(stream_bytes)
902
            for [name], record_bytes in parser.read_pending_records():
903
                names.append(name)
904
                # The bytes should be a valid bencoded string.
905
                bencode.bdecode(record_bytes)
906
                # XXX: assert that the bencoded knit records have the right
907
                # contents?
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
908
        
2535.3.40 by Andrew Bennetts
Tidy up more XXXs.
909
    def test_no_such_revision_error(self):
910
        backing = self.get_transport()
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
911
        request = smart.repository.SmartServerRepositoryStreamRevisionsChunked(
912
            backing)
2535.3.40 by Andrew Bennetts
Tidy up more XXXs.
913
        repo = self.make_repository('.')
914
        rev_id1_utf8 = u'\xc8'.encode('utf-8')
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.
915
        response = request.execute(backing.local_abspath(''))
916
        self.assertEqual(None, response)
917
        response = request.do_body("%s\n\n1" % (rev_id1_utf8,))
918
        self.assertEqual(
919
            FailedSmartServerResponse(('NoSuchRevision', )),
920
            response)
921
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
922
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.
923
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
924
925
    def test_is_readonly_no(self):
926
        backing = self.get_transport()
927
        request = smart.request.SmartServerIsReadonly(backing)
928
        response = request.execute()
929
        self.assertEqual(
930
            SmartServerResponse(('no',)), response)
931
932
    def test_is_readonly_yes(self):
933
        backing = self.get_readonly_transport()
934
        request = smart.request.SmartServerIsReadonly(backing)
935
        response = request.execute()
936
        self.assertEqual(
937
            SmartServerResponse(('yes',)), response)
938
939
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
940
class TestHandlers(tests.TestCase):
941
    """Tests for the request.request_handlers object."""
942
943
    def test_registered_methods(self):
944
        """Test that known methods are registered to the correct object."""
945
        self.assertEqual(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
946
            smart.request.request_handlers.get('Branch.get_config_file'),
947
            smart.branch.SmartServerBranchGetConfigFile)
948
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
949
            smart.request.request_handlers.get('Branch.lock_write'),
950
            smart.branch.SmartServerBranchRequestLockWrite)
951
        self.assertEqual(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
952
            smart.request.request_handlers.get('Branch.last_revision_info'),
953
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
954
        self.assertEqual(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
955
            smart.request.request_handlers.get('Branch.revision_history'),
956
            smart.branch.SmartServerRequestRevisionHistory)
957
        self.assertEqual(
2018.5.77 by Wouter van Heyst
Fix typo in request_handlers registration of Branch.set_last_revision, and test that registration
958
            smart.request.request_handlers.get('Branch.set_last_revision'),
959
            smart.branch.SmartServerBranchRequestSetLastRevision)
960
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
961
            smart.request.request_handlers.get('Branch.unlock'),
962
            smart.branch.SmartServerBranchRequestUnlock)
963
        self.assertEqual(
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
964
            smart.request.request_handlers.get('BzrDir.find_repository'),
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
965
            smart.bzrdir.SmartServerRequestFindRepositoryV1)
966
        self.assertEqual(
967
            smart.request.request_handlers.get('BzrDir.find_repositoryV2'),
968
            smart.bzrdir.SmartServerRequestFindRepositoryV2)
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
969
        self.assertEqual(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
970
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
971
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
972
        self.assertEqual(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
973
            smart.request.request_handlers.get('BzrDir.open_branch'),
974
            smart.bzrdir.SmartServerRequestOpenBranch)
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
975
        self.assertEqual(
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
976
            smart.request.request_handlers.get('Repository.gather_stats'),
977
            smart.repository.SmartServerRepositoryGatherStats)
978
        self.assertEqual(
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
979
            smart.request.request_handlers.get('Repository.get_parent_map'),
980
            smart.repository.SmartServerRepositoryGetParentMap)
981
        self.assertEqual(
2535.3.69 by Andrew Bennetts
Add check for Repository.stream_knit_data_for_revisions to TestHandlers.test_registered_methods.
982
            smart.request.request_handlers.get(
983
                'Repository.get_revision_graph'),
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
984
            smart.repository.SmartServerRepositoryGetRevisionGraph)
985
        self.assertEqual(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
986
            smart.request.request_handlers.get('Repository.has_revision'),
987
            smart.repository.SmartServerRequestHasRevision)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
988
        self.assertEqual(
989
            smart.request.request_handlers.get('Repository.is_shared'),
990
            smart.repository.SmartServerRepositoryIsShared)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
991
        self.assertEqual(
992
            smart.request.request_handlers.get('Repository.lock_write'),
993
            smart.repository.SmartServerRepositoryLockWrite)
994
        self.assertEqual(
2535.3.69 by Andrew Bennetts
Add check for Repository.stream_knit_data_for_revisions to TestHandlers.test_registered_methods.
995
            smart.request.request_handlers.get('Repository.tarball'),
996
            smart.repository.SmartServerRepositoryTarball)
997
        self.assertEqual(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
998
            smart.request.request_handlers.get('Repository.unlock'),
999
            smart.repository.SmartServerRepositoryUnlock)
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.
1000
        self.assertEqual(
1001
            smart.request.request_handlers.get('Transport.is_readonly'),
1002
            smart.request.SmartServerIsReadonly)