/brz/remove-bazaar

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