/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

  • Committer: Robert Collins
  • Date: 2008-04-09 20:13:46 UTC
  • mto: This revision was merged to the branch mainline in revision 3350.
  • Revision ID: robertc@robertcollins.net-20080409201346-2m5dpim3cowzwacs
Spelling in NEWS.

Show diffs side-by-side

added added

removed removed

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