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