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