~bzr-pqm/bzr/bzr.dev

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