~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
"""
26
26
 
27
27
import bz2
28
 
from cStringIO import StringIO
29
 
import tarfile
 
28
import zlib
30
29
 
31
30
from bzrlib import (
32
 
    bencode,
33
31
    branch as _mod_branch,
34
32
    bzrdir,
35
33
    errors,
36
 
    pack,
 
34
    gpg,
 
35
    inventory_delta,
37
36
    tests,
38
37
    transport,
39
38
    urlutils,
48
47
    server,
49
48
    vfs,
50
49
    )
 
50
from bzrlib.testament import Testament
51
51
from bzrlib.tests import test_server
52
52
from bzrlib.transport import (
53
53
    chroot,
89
89
            backing_transport = tests.TestCaseWithTransport.get_transport(self)
90
90
            self._chroot_server = chroot.ChrootServer(backing_transport)
91
91
            self.start_server(self._chroot_server)
92
 
        t = transport.get_transport(self._chroot_server.get_url())
 
92
        t = transport.get_transport_from_url(self._chroot_server.get_url())
93
93
        if relpath is not None:
94
94
            t = t.clone(relpath)
95
95
        return t
103
103
        # the default or a parameterized class, but rather use the
104
104
        # TestCaseWithTransport infrastructure to set up a smart server and
105
105
        # transport.
106
 
        self.transport_server = self.make_transport_server
 
106
        self.overrideAttr(self, "transport_server", self.make_transport_server)
107
107
 
108
108
    def make_transport_server(self):
109
109
        return test_server.SmartTCPServer_for_testing('-' + self.id())
225
225
        self.assertEqual(expected, request.execute('', 'False'))
226
226
 
227
227
 
 
228
class TestSmartServerBzrDirRequestCloningMetaDir(
 
229
    tests.TestCaseWithMemoryTransport):
 
230
    """Tests for BzrDir.checkout_metadir."""
 
231
 
 
232
    def test_checkout_metadir(self):
 
233
        backing = self.get_transport()
 
234
        request = smart_dir.SmartServerBzrDirRequestCheckoutMetaDir(
 
235
            backing)
 
236
        branch = self.make_branch('.', format='2a')
 
237
        response = request.execute('')
 
238
        self.assertEqual(
 
239
            smart_req.SmartServerResponse(
 
240
                ('Bazaar-NG meta directory, format 1\n',
 
241
                 'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
242
                 'Bazaar Branch Format 7 (needs bzr 1.6)\n')),
 
243
            response)
 
244
 
 
245
 
 
246
class TestSmartServerBzrDirRequestDestroyBranch(
 
247
    tests.TestCaseWithMemoryTransport):
 
248
    """Tests for BzrDir.destroy_branch."""
 
249
 
 
250
    def test_destroy_branch_default(self):
 
251
        """The default branch can be removed."""
 
252
        backing = self.get_transport()
 
253
        dir = self.make_branch('.').bzrdir
 
254
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
255
        request = request_class(backing)
 
256
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
257
        self.assertEqual(expected, request.execute('', None))
 
258
 
 
259
    def test_destroy_branch_named(self):
 
260
        """A named branch can be removed."""
 
261
        backing = self.get_transport()
 
262
        dir = self.make_repository('.', format="development-colo").bzrdir
 
263
        dir.create_branch(name="branchname")
 
264
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
265
        request = request_class(backing)
 
266
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
267
        self.assertEqual(expected, request.execute('', "branchname"))
 
268
 
 
269
    def test_destroy_branch_missing(self):
 
270
        """An error is raised if the branch didn't exist."""
 
271
        backing = self.get_transport()
 
272
        dir = self.make_bzrdir('.', format="development-colo")
 
273
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
274
        request = request_class(backing)
 
275
        expected = smart_req.FailedSmartServerResponse(('nobranch',), None)
 
276
        self.assertEqual(expected, request.execute('', "branchname"))
 
277
 
 
278
 
 
279
class TestSmartServerBzrDirRequestHasWorkingTree(
 
280
    tests.TestCaseWithTransport):
 
281
    """Tests for BzrDir.has_workingtree."""
 
282
 
 
283
    def test_has_workingtree_yes(self):
 
284
        """A working tree is present."""
 
285
        backing = self.get_transport()
 
286
        dir = self.make_branch_and_tree('.').bzrdir
 
287
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
288
        request = request_class(backing)
 
289
        expected = smart_req.SuccessfulSmartServerResponse(('yes',))
 
290
        self.assertEqual(expected, request.execute(''))
 
291
 
 
292
    def test_has_workingtree_no(self):
 
293
        """A working tree is missing."""
 
294
        backing = self.get_transport()
 
295
        dir = self.make_bzrdir('.')
 
296
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
297
        request = request_class(backing)
 
298
        expected = smart_req.SuccessfulSmartServerResponse(('no',))
 
299
        self.assertEqual(expected, request.execute(''))
 
300
 
 
301
 
 
302
class TestSmartServerBzrDirRequestDestroyRepository(
 
303
    tests.TestCaseWithMemoryTransport):
 
304
    """Tests for BzrDir.destroy_repository."""
 
305
 
 
306
    def test_destroy_repository_default(self):
 
307
        """The repository can be removed."""
 
308
        backing = self.get_transport()
 
309
        dir = self.make_repository('.').bzrdir
 
310
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
311
        request = request_class(backing)
 
312
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
313
        self.assertEqual(expected, request.execute(''))
 
314
 
 
315
    def test_destroy_repository_missing(self):
 
316
        """An error is raised if the repository didn't exist."""
 
317
        backing = self.get_transport()
 
318
        dir = self.make_bzrdir('.')
 
319
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
320
        request = request_class(backing)
 
321
        expected = smart_req.FailedSmartServerResponse(
 
322
            ('norepository',), None)
 
323
        self.assertEqual(expected, request.execute(''))
 
324
 
 
325
 
228
326
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
229
327
    """Tests for BzrDir.create_repository."""
230
328
 
739
837
            request.execute(''))
740
838
 
741
839
 
 
840
class TestSmartServerBranchRequestRevisionIdToRevno(
 
841
    tests.TestCaseWithMemoryTransport):
 
842
 
 
843
    def test_null(self):
 
844
        backing = self.get_transport()
 
845
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
846
            backing)
 
847
        self.make_branch('.')
 
848
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0')),
 
849
            request.execute('', 'null:'))
 
850
 
 
851
    def test_simple(self):
 
852
        backing = self.get_transport()
 
853
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
854
            backing)
 
855
        tree = self.make_branch_and_memory_tree('.')
 
856
        tree.lock_write()
 
857
        tree.add('')
 
858
        r1 = tree.commit('1st commit')
 
859
        tree.unlock()
 
860
        self.assertEqual(
 
861
            smart_req.SmartServerResponse(('ok', '1')),
 
862
            request.execute('', r1))
 
863
 
 
864
    def test_not_found(self):
 
865
        backing = self.get_transport()
 
866
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
867
            backing)
 
868
        branch = self.make_branch('.')
 
869
        self.assertEqual(
 
870
            smart_req.FailedSmartServerResponse(
 
871
                ('NoSuchRevision', 'idontexist')),
 
872
            request.execute('', 'idontexist'))
 
873
 
 
874
 
742
875
class TestSmartServerBranchRequestGetConfigFile(
743
876
    tests.TestCaseWithMemoryTransport):
744
877
 
767
900
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
768
901
 
769
902
    def get_lock_tokens(self, branch):
770
 
        branch_token = branch.lock_write()
771
 
        repo_token = branch.repository.lock_write()
 
903
        branch_token = branch.lock_write().branch_token
 
904
        repo_token = branch.repository.lock_write().repository_token
772
905
        branch.repository.unlock()
773
906
        return branch_token, repo_token
774
907
 
775
908
 
 
909
class TestSmartServerBranchRequestPutConfigFile(TestLockedBranch):
 
910
 
 
911
    def test_with_content(self):
 
912
        backing = self.get_transport()
 
913
        request = smart_branch.SmartServerBranchPutConfigFile(backing)
 
914
        branch = self.make_branch('.')
 
915
        branch_token, repo_token = self.get_lock_tokens(branch)
 
916
        self.assertIs(None, request.execute('', branch_token, repo_token))
 
917
        self.assertEqual(
 
918
            smart_req.SmartServerResponse(('ok', )),
 
919
            request.do_body('foo bar baz'))
 
920
        self.assertEquals(
 
921
            branch.control_transport.get_bytes('branch.conf'),
 
922
            'foo bar baz')
 
923
        branch.unlock()
 
924
 
 
925
 
776
926
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
777
927
 
778
928
    def test_value_name(self):
802
952
        branch.unlock()
803
953
 
804
954
 
 
955
class TestSmartServerBranchRequestSetConfigOptionDict(TestLockedBranch):
 
956
 
 
957
    def setUp(self):
 
958
        TestLockedBranch.setUp(self)
 
959
        # A dict with non-ascii keys and values to exercise unicode
 
960
        # roundtripping.
 
961
        self.encoded_value_dict = (
 
962
            'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde')
 
963
        self.value_dict = {
 
964
            'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
965
 
 
966
    def test_value_name(self):
 
967
        branch = self.make_branch('.')
 
968
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
969
            branch.bzrdir.root_transport)
 
970
        branch_token, repo_token = self.get_lock_tokens(branch)
 
971
        config = branch._get_config()
 
972
        result = request.execute('', branch_token, repo_token,
 
973
            self.encoded_value_dict, 'foo', '')
 
974
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
975
        self.assertEqual(self.value_dict, config.get_option('foo'))
 
976
        # Cleanup
 
977
        branch.unlock()
 
978
 
 
979
    def test_value_name_section(self):
 
980
        branch = self.make_branch('.')
 
981
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
982
            branch.bzrdir.root_transport)
 
983
        branch_token, repo_token = self.get_lock_tokens(branch)
 
984
        config = branch._get_config()
 
985
        result = request.execute('', branch_token, repo_token,
 
986
            self.encoded_value_dict, 'foo', 'gam')
 
987
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
988
        self.assertEqual(self.value_dict, config.get_option('foo', 'gam'))
 
989
        # Cleanup
 
990
        branch.unlock()
 
991
 
 
992
 
805
993
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
806
994
    # Only called when the branch format and tags match [yay factory
807
995
    # methods] so only need to test straight forward cases.
898
1086
        # its repository.
899
1087
        self.make_tree_with_two_commits()
900
1088
        rev_id_utf8 = u'\xc8'.encode('utf-8')
901
 
        self.tree.branch.set_revision_history([])
 
1089
        self.tree.branch.set_last_revision_info(0, 'null:')
902
1090
        self.assertEqual(
903
1091
            (0, 'null:'), self.tree.branch.last_revision_info())
904
1092
        # We can update the branch to a revision that is present in the
1054
1242
        self.assertEqual('child-1', self.tree.branch.last_revision())
1055
1243
 
1056
1244
 
 
1245
class TestSmartServerBranchBreakLock(tests.TestCaseWithMemoryTransport):
 
1246
 
 
1247
    def test_lock_to_break(self):
 
1248
        base_branch = self.make_branch('base')
 
1249
        request = smart_branch.SmartServerBranchBreakLock(
 
1250
            self.get_transport())
 
1251
        base_branch.lock_write()
 
1252
        self.assertEqual(
 
1253
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1254
            request.execute('base'))
 
1255
 
 
1256
    def test_nothing_to_break(self):
 
1257
        base_branch = self.make_branch('base')
 
1258
        request = smart_branch.SmartServerBranchBreakLock(
 
1259
            self.get_transport())
 
1260
        self.assertEqual(
 
1261
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1262
            request.execute('base'))
 
1263
 
 
1264
 
1057
1265
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
1058
1266
 
1059
1267
    def test_get_parent_none(self):
1073
1281
            response)
1074
1282
 
1075
1283
 
1076
 
class TestSmartServerBranchRequestSetParent(tests.TestCaseWithMemoryTransport):
 
1284
class TestSmartServerBranchRequestSetParent(TestLockedBranch):
1077
1285
 
1078
1286
    def test_set_parent_none(self):
1079
1287
        branch = self.make_branch('base', format="1.9")
1082
1290
        branch.unlock()
1083
1291
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
1084
1292
            self.get_transport())
1085
 
        branch_token = branch.lock_write()
1086
 
        repo_token = branch.repository.lock_write()
 
1293
        branch_token, repo_token = self.get_lock_tokens(branch)
1087
1294
        try:
1088
1295
            response = request.execute('base', branch_token, repo_token, '')
1089
1296
        finally:
1090
 
            branch.repository.unlock()
1091
1297
            branch.unlock()
1092
1298
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1299
        # Refresh branch as SetParentLocation modified it
 
1300
        branch = branch.bzrdir.open_branch()
1093
1301
        self.assertEqual(None, branch.get_parent())
1094
1302
 
1095
1303
    def test_set_parent_something(self):
1096
1304
        branch = self.make_branch('base', format="1.9")
1097
1305
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
1098
1306
            self.get_transport())
1099
 
        branch_token = branch.lock_write()
1100
 
        repo_token = branch.repository.lock_write()
 
1307
        branch_token, repo_token = self.get_lock_tokens(branch)
1101
1308
        try:
1102
1309
            response = request.execute('base', branch_token, repo_token,
1103
 
            'http://bar/')
 
1310
                                       'http://bar/')
1104
1311
        finally:
1105
 
            branch.repository.unlock()
1106
1312
            branch.unlock()
1107
1313
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
1108
 
        self.assertEqual('http://bar/', branch.get_parent())
 
1314
        refreshed = _mod_branch.Branch.open(branch.base)
 
1315
        self.assertEqual('http://bar/', refreshed.get_parent())
1109
1316
 
1110
1317
 
1111
1318
class TestSmartServerBranchRequestGetTagsBytes(
1137
1344
            response)
1138
1345
 
1139
1346
 
1140
 
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithMemoryTransport):
 
1347
class TestSmartServerBranchRequestLockWrite(TestLockedBranch):
1141
1348
 
1142
1349
    def setUp(self):
1143
1350
        tests.TestCaseWithMemoryTransport.setUp(self)
1165
1372
        backing = self.get_transport()
1166
1373
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1167
1374
        branch = self.make_branch('.')
1168
 
        branch_token = branch.lock_write()
 
1375
        branch_token = branch.lock_write().branch_token
1169
1376
        branch.leave_lock_in_place()
1170
1377
        branch.unlock()
1171
1378
        response = request.execute('')
1180
1387
        backing = self.get_transport()
1181
1388
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1182
1389
        branch = self.make_branch('.', format='knit')
1183
 
        branch_token = branch.lock_write()
1184
 
        repo_token = branch.repository.lock_write()
1185
 
        branch.repository.unlock()
 
1390
        branch_token, repo_token = self.get_lock_tokens(branch)
1186
1391
        branch.leave_lock_in_place()
1187
1392
        branch.repository.leave_lock_in_place()
1188
1393
        branch.unlock()
1203
1408
        backing = self.get_transport()
1204
1409
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1205
1410
        branch = self.make_branch('.', format='knit')
1206
 
        branch_token = branch.lock_write()
1207
 
        repo_token = branch.repository.lock_write()
1208
 
        branch.repository.unlock()
 
1411
        branch_token, repo_token = self.get_lock_tokens(branch)
1209
1412
        branch.leave_lock_in_place()
1210
1413
        branch.repository.leave_lock_in_place()
1211
1414
        branch.unlock()
1226
1429
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
1227
1430
        branch = self.make_branch('.', format='knit')
1228
1431
        repo = branch.repository
1229
 
        repo_token = repo.lock_write()
 
1432
        repo_token = repo.lock_write().repository_token
1230
1433
        repo.leave_lock_in_place()
1231
1434
        repo.unlock()
1232
1435
        response = request.execute('')
1249
1452
        self.assertEqual('LockFailed', error_name)
1250
1453
 
1251
1454
 
1252
 
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithMemoryTransport):
 
1455
class TestSmartServerBranchRequestGetPhysicalLockStatus(TestLockedBranch):
 
1456
 
 
1457
    def setUp(self):
 
1458
        tests.TestCaseWithMemoryTransport.setUp(self)
 
1459
 
 
1460
    def test_true(self):
 
1461
        backing = self.get_transport()
 
1462
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1463
            backing)
 
1464
        branch = self.make_branch('.')
 
1465
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1466
        self.assertEquals(True, branch.get_physical_lock_status())
 
1467
        response = request.execute('')
 
1468
        self.assertEqual(
 
1469
            smart_req.SmartServerResponse(('yes',)), response)
 
1470
        branch.unlock()
 
1471
 
 
1472
    def test_false(self):
 
1473
        backing = self.get_transport()
 
1474
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1475
            backing)
 
1476
        branch = self.make_branch('.')
 
1477
        self.assertEquals(False, branch.get_physical_lock_status())
 
1478
        response = request.execute('')
 
1479
        self.assertEqual(
 
1480
            smart_req.SmartServerResponse(('no',)), response)
 
1481
 
 
1482
 
 
1483
class TestSmartServerBranchRequestUnlock(TestLockedBranch):
1253
1484
 
1254
1485
    def setUp(self):
1255
1486
        tests.TestCaseWithMemoryTransport.setUp(self)
1259
1490
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
1260
1491
        branch = self.make_branch('.', format='knit')
1261
1492
        # Lock the branch
1262
 
        branch_token = branch.lock_write()
1263
 
        repo_token = branch.repository.lock_write()
1264
 
        branch.repository.unlock()
 
1493
        branch_token, repo_token = self.get_lock_tokens(branch)
1265
1494
        # Unlock the branch (and repo) object, leaving the physical locks
1266
1495
        # in place.
1267
1496
        branch.leave_lock_in_place()
1291
1520
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
1292
1521
        branch = self.make_branch('.', format='knit')
1293
1522
        # Lock the repository.
1294
 
        repo_token = branch.repository.lock_write()
 
1523
        repo_token = branch.repository.lock_write().repository_token
1295
1524
        branch.repository.leave_lock_in_place()
1296
1525
        branch.repository.unlock()
1297
1526
        # Issue branch lock_write request on the unlocked branch (with locked
1298
1527
        # repo).
1299
 
        response = request.execute(
1300
 
            '', 'branch token', repo_token)
 
1528
        response = request.execute('', 'branch token', repo_token)
1301
1529
        self.assertEqual(
1302
1530
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
1303
1531
        # Cleanup
1322
1550
            request.execute, 'subdir')
1323
1551
 
1324
1552
 
 
1553
class TestSmartServerRepositoryAddSignatureText(tests.TestCaseWithMemoryTransport):
 
1554
 
 
1555
    def test_add_text(self):
 
1556
        backing = self.get_transport()
 
1557
        request = smart_repo.SmartServerRepositoryAddSignatureText(backing)
 
1558
        tree = self.make_branch_and_memory_tree('.')
 
1559
        write_token = tree.lock_write()
 
1560
        self.addCleanup(tree.unlock)
 
1561
        tree.add('')
 
1562
        tree.commit("Message", rev_id='rev1')
 
1563
        tree.branch.repository.start_write_group()
 
1564
        write_group_tokens = tree.branch.repository.suspend_write_group()
 
1565
        self.assertEqual(None, request.execute('', write_token,
 
1566
            'rev1', *write_group_tokens))
 
1567
        response = request.do_body('somesignature')
 
1568
        self.assertTrue(response.is_successful())
 
1569
        self.assertEqual(response.args[0], 'ok')
 
1570
        write_group_tokens = response.args[1:]
 
1571
        tree.branch.repository.resume_write_group(write_group_tokens)
 
1572
        tree.branch.repository.commit_write_group()
 
1573
        tree.unlock()
 
1574
        self.assertEqual("somesignature",
 
1575
            tree.branch.repository.get_signature_text("rev1"))
 
1576
 
 
1577
 
 
1578
class TestSmartServerRepositoryAllRevisionIds(
 
1579
    tests.TestCaseWithMemoryTransport):
 
1580
 
 
1581
    def test_empty(self):
 
1582
        """An empty body should be returned for an empty repository."""
 
1583
        backing = self.get_transport()
 
1584
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1585
        self.make_repository('.')
 
1586
        self.assertEquals(
 
1587
            smart_req.SuccessfulSmartServerResponse(("ok", ), ""),
 
1588
            request.execute(''))
 
1589
 
 
1590
    def test_some_revisions(self):
 
1591
        """An empty body should be returned for an empty repository."""
 
1592
        backing = self.get_transport()
 
1593
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1594
        tree = self.make_branch_and_memory_tree('.')
 
1595
        tree.lock_write()
 
1596
        tree.add('')
 
1597
        tree.commit(rev_id='origineel', message="message")
 
1598
        tree.commit(rev_id='nog-een-revisie', message="message")
 
1599
        tree.unlock()
 
1600
        self.assertEquals(
 
1601
            smart_req.SuccessfulSmartServerResponse(("ok", ),
 
1602
                "origineel\nnog-een-revisie"),
 
1603
            request.execute(''))
 
1604
 
 
1605
 
 
1606
class TestSmartServerRepositoryBreakLock(tests.TestCaseWithMemoryTransport):
 
1607
 
 
1608
    def test_lock_to_break(self):
 
1609
        backing = self.get_transport()
 
1610
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1611
        tree = self.make_branch_and_memory_tree('.')
 
1612
        tree.branch.repository.lock_write()
 
1613
        self.assertEqual(
 
1614
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1615
            request.execute(''))
 
1616
 
 
1617
    def test_nothing_to_break(self):
 
1618
        backing = self.get_transport()
 
1619
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1620
        tree = self.make_branch_and_memory_tree('.')
 
1621
        self.assertEqual(
 
1622
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1623
            request.execute(''))
 
1624
 
 
1625
 
1325
1626
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
1326
1627
 
1327
1628
    def test_trivial_bzipped(self):
1447
1748
            request.execute('stacked', 1, (3, r3)))
1448
1749
 
1449
1750
 
1450
 
class TestSmartServerRepositoryGetStream(tests.TestCaseWithMemoryTransport):
 
1751
class TestSmartServerRepositoryIterRevisions(
 
1752
    tests.TestCaseWithMemoryTransport):
 
1753
 
 
1754
    def test_basic(self):
 
1755
        backing = self.get_transport()
 
1756
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1757
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1758
        tree.lock_write()
 
1759
        tree.add('')
 
1760
        tree.commit('1st commit', rev_id="rev1")
 
1761
        tree.commit('2nd commit', rev_id="rev2")
 
1762
        tree.unlock()
 
1763
 
 
1764
        self.assertIs(None, request.execute(''))
 
1765
        response = request.do_body("rev1\nrev2")
 
1766
        self.assertTrue(response.is_successful())
 
1767
        # Format 2a uses serializer format 10
 
1768
        self.assertEquals(response.args, ("ok", "10"))
 
1769
 
 
1770
        self.addCleanup(tree.branch.lock_read().unlock)
 
1771
        entries = [zlib.compress(record.get_bytes_as("fulltext")) for record in
 
1772
            tree.branch.repository.revisions.get_record_stream(
 
1773
            [("rev1", ), ("rev2", )], "unordered", True)]
 
1774
 
 
1775
        contents = "".join(response.body_stream)
 
1776
        self.assertTrue(contents in (
 
1777
            "".join([entries[0], entries[1]]),
 
1778
            "".join([entries[1], entries[0]])))
 
1779
 
 
1780
    def test_missing(self):
 
1781
        backing = self.get_transport()
 
1782
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1783
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1784
 
 
1785
        self.assertIs(None, request.execute(''))
 
1786
        response = request.do_body("rev1\nrev2")
 
1787
        self.assertTrue(response.is_successful())
 
1788
        # Format 2a uses serializer format 10
 
1789
        self.assertEquals(response.args, ("ok", "10"))
 
1790
 
 
1791
        contents = "".join(response.body_stream)
 
1792
        self.assertEquals(contents, "")
 
1793
 
 
1794
 
 
1795
class GetStreamTestBase(tests.TestCaseWithMemoryTransport):
1451
1796
 
1452
1797
    def make_two_commit_repo(self):
1453
1798
        tree = self.make_branch_and_memory_tree('.')
1459
1804
        repo = tree.branch.repository
1460
1805
        return repo, r1, r2
1461
1806
 
 
1807
 
 
1808
class TestSmartServerRepositoryGetStream(GetStreamTestBase):
 
1809
 
1462
1810
    def test_ancestry_of(self):
1463
1811
        """The search argument may be a 'ancestry-of' some heads'."""
1464
1812
        backing = self.get_transport()
1485
1833
        stream_bytes = ''.join(response.body_stream)
1486
1834
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
1487
1835
 
 
1836
    def test_search_everything(self):
 
1837
        """A search of 'everything' returns a stream."""
 
1838
        backing = self.get_transport()
 
1839
        request = smart_repo.SmartServerRepositoryGetStream_1_19(backing)
 
1840
        repo, r1, r2 = self.make_two_commit_repo()
 
1841
        serialised_fetch_spec = 'everything'
 
1842
        request.execute('', repo._format.network_name())
 
1843
        response = request.do_body(serialised_fetch_spec)
 
1844
        self.assertEqual(('ok',), response.args)
 
1845
        stream_bytes = ''.join(response.body_stream)
 
1846
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1847
 
1488
1848
 
1489
1849
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
1490
1850
 
1511
1871
            request.execute('', rev_id_utf8))
1512
1872
 
1513
1873
 
 
1874
class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
 
1875
 
 
1876
    def test_single(self):
 
1877
        backing = self.get_transport()
 
1878
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1879
        t = self.make_branch_and_tree('.')
 
1880
        self.addCleanup(t.lock_write().unlock)
 
1881
        self.build_tree_contents([("file", "somecontents")])
 
1882
        t.add(["file"], ["thefileid"])
 
1883
        t.commit(rev_id='somerev', message="add file")
 
1884
        self.assertIs(None, request.execute(''))
 
1885
        response = request.do_body("thefileid\0somerev\n")
 
1886
        self.assertTrue(response.is_successful())
 
1887
        self.assertEquals(response.args, ("ok", ))
 
1888
        self.assertEquals("".join(response.body_stream),
 
1889
            "ok\x000\n" + zlib.compress("somecontents"))
 
1890
 
 
1891
    def test_missing(self):
 
1892
        backing = self.get_transport()
 
1893
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1894
        t = self.make_branch_and_tree('.')
 
1895
        self.addCleanup(t.lock_write().unlock)
 
1896
        self.assertIs(None, request.execute(''))
 
1897
        response = request.do_body("thefileid\0revision\n")
 
1898
        self.assertTrue(response.is_successful())
 
1899
        self.assertEquals(response.args, ("ok", ))
 
1900
        self.assertEquals("".join(response.body_stream),
 
1901
            "absent\x00thefileid\x00revision\x000\n")
 
1902
 
 
1903
 
 
1904
class TestSmartServerRequestHasSignatureForRevisionId(
 
1905
        tests.TestCaseWithMemoryTransport):
 
1906
 
 
1907
    def test_missing_revision(self):
 
1908
        """For a missing revision, NoSuchRevision is returned."""
 
1909
        backing = self.get_transport()
 
1910
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1911
            backing)
 
1912
        self.make_repository('.')
 
1913
        self.assertEqual(
 
1914
            smart_req.FailedSmartServerResponse(
 
1915
                ('nosuchrevision', 'revid'), None),
 
1916
            request.execute('', 'revid'))
 
1917
 
 
1918
    def test_missing_signature(self):
 
1919
        """For a missing signature, ('no', ) is returned."""
 
1920
        backing = self.get_transport()
 
1921
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1922
            backing)
 
1923
        tree = self.make_branch_and_memory_tree('.')
 
1924
        tree.lock_write()
 
1925
        tree.add('')
 
1926
        r1 = tree.commit('a commit', rev_id='A')
 
1927
        tree.unlock()
 
1928
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1929
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1930
            request.execute('', 'A'))
 
1931
 
 
1932
    def test_present_signature(self):
 
1933
        """For a present signature, ('yes', ) is returned."""
 
1934
        backing = self.get_transport()
 
1935
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1936
            backing)
 
1937
        strategy = gpg.LoopbackGPGStrategy(None)
 
1938
        tree = self.make_branch_and_memory_tree('.')
 
1939
        tree.lock_write()
 
1940
        tree.add('')
 
1941
        r1 = tree.commit('a commit', rev_id='A')
 
1942
        tree.branch.repository.start_write_group()
 
1943
        tree.branch.repository.sign_revision('A', strategy)
 
1944
        tree.branch.repository.commit_write_group()
 
1945
        tree.unlock()
 
1946
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1947
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1948
            request.execute('', 'A'))
 
1949
 
 
1950
 
1514
1951
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
1515
1952
 
1516
1953
    def test_empty_revid(self):
1569
2006
                         request.execute('',
1570
2007
                                         rev_id_utf8, 'yes'))
1571
2008
 
 
2009
    def test_unknown_revid(self):
 
2010
        """An unknown revision id causes a 'nosuchrevision' error."""
 
2011
        backing = self.get_transport()
 
2012
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
 
2013
        repository = self.make_repository('.')
 
2014
        expected_body = 'revisions: 0\n'
 
2015
        self.assertEqual(
 
2016
            smart_req.FailedSmartServerResponse(
 
2017
                ('nosuchrevision', 'mia'), None),
 
2018
            request.execute('', 'mia', 'yes'))
 
2019
 
1572
2020
 
1573
2021
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
1574
2022
 
1589
2037
            request.execute('', ))
1590
2038
 
1591
2039
 
 
2040
class TestSmartServerRepositoryGetRevisionSignatureText(
 
2041
        tests.TestCaseWithMemoryTransport):
 
2042
 
 
2043
    def test_get_signature(self):
 
2044
        backing = self.get_transport()
 
2045
        request = smart_repo.SmartServerRepositoryGetRevisionSignatureText(
 
2046
            backing)
 
2047
        bb = self.make_branch_builder('.')
 
2048
        bb.build_commit(rev_id='A')
 
2049
        repo = bb.get_branch().repository
 
2050
        strategy = gpg.LoopbackGPGStrategy(None)
 
2051
        self.addCleanup(repo.lock_write().unlock)
 
2052
        repo.start_write_group()
 
2053
        repo.sign_revision('A', strategy)
 
2054
        repo.commit_write_group()
 
2055
        expected_body = (
 
2056
            '-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
 
2057
            Testament.from_revision(repo, 'A').as_short_text() +
 
2058
            '-----END PSEUDO-SIGNED CONTENT-----\n')
 
2059
        self.assertEqual(
 
2060
            smart_req.SmartServerResponse(('ok', ), expected_body),
 
2061
            request.execute('', 'A'))
 
2062
 
 
2063
 
 
2064
class TestSmartServerRepositoryMakeWorkingTrees(
 
2065
        tests.TestCaseWithMemoryTransport):
 
2066
 
 
2067
    def test_make_working_trees(self):
 
2068
        """For a repository with working trees, ('yes', ) is returned."""
 
2069
        backing = self.get_transport()
 
2070
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2071
        r = self.make_repository('.')
 
2072
        r.set_make_working_trees(True)
 
2073
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2074
            request.execute('', ))
 
2075
 
 
2076
    def test_is_not_shared(self):
 
2077
        """For a repository with working trees, ('no', ) is returned."""
 
2078
        backing = self.get_transport()
 
2079
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2080
        r = self.make_repository('.')
 
2081
        r.set_make_working_trees(False)
 
2082
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2083
            request.execute('', ))
 
2084
 
 
2085
 
1592
2086
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
1593
2087
 
1594
2088
    def test_lock_write_on_unlocked_repo(self):
1610
2104
        backing = self.get_transport()
1611
2105
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
1612
2106
        repository = self.make_repository('.', format='knit')
1613
 
        repo_token = repository.lock_write()
 
2107
        repo_token = repository.lock_write().repository_token
1614
2108
        repository.leave_lock_in_place()
1615
2109
        repository.unlock()
1616
2110
        response = request.execute('')
1658
2152
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
1659
2153
            backing)
1660
2154
        repository = self.make_repository('.', format='knit')
1661
 
        lock_token = repository.lock_write()
 
2155
        lock_token = repository.lock_write().repository_token
1662
2156
        response = request.execute('', '', lock_token)
1663
2157
        self.assertEqual(None, response)
1664
2158
        response = request.do_chunk(self.make_empty_byte_stream(repository))
1672
2166
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
1673
2167
            backing)
1674
2168
        repository = self.make_repository('.', format='knit')
1675
 
        lock_token = repository.lock_write()
 
2169
        lock_token = repository.lock_write().repository_token
1676
2170
        self.assertRaises(
1677
2171
            errors.TokenMismatch, request.execute, '', '', 'wrong-token')
1678
2172
        repository.unlock()
1687
2181
        backing = self.get_transport()
1688
2182
        request = smart_repo.SmartServerRepositoryUnlock(backing)
1689
2183
        repository = self.make_repository('.', format='knit')
1690
 
        token = repository.lock_write()
 
2184
        token = repository.lock_write().repository_token
1691
2185
        repository.leave_lock_in_place()
1692
2186
        repository.unlock()
1693
2187
        response = request.execute('', token)
1708
2202
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
1709
2203
 
1710
2204
 
 
2205
class TestSmartServerRepositoryGetPhysicalLockStatus(
 
2206
    tests.TestCaseWithTransport):
 
2207
 
 
2208
    def test_with_write_lock(self):
 
2209
        backing = self.get_transport()
 
2210
        repo = self.make_repository('.')
 
2211
        self.addCleanup(repo.lock_write().unlock)
 
2212
        # lock_write() doesn't necessarily actually take a physical
 
2213
        # lock out.
 
2214
        if repo.get_physical_lock_status():
 
2215
            expected = 'yes'
 
2216
        else:
 
2217
            expected = 'no'
 
2218
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2219
        request = request_class(backing)
 
2220
        self.assertEqual(smart_req.SuccessfulSmartServerResponse((expected,)),
 
2221
            request.execute('', ))
 
2222
 
 
2223
    def test_without_write_lock(self):
 
2224
        backing = self.get_transport()
 
2225
        repo = self.make_repository('.')
 
2226
        self.assertEquals(False, repo.get_physical_lock_status())
 
2227
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2228
        request = request_class(backing)
 
2229
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('no',)),
 
2230
            request.execute('', ))
 
2231
 
 
2232
 
 
2233
class TestSmartServerRepositoryReconcile(tests.TestCaseWithTransport):
 
2234
 
 
2235
    def test_reconcile(self):
 
2236
        backing = self.get_transport()
 
2237
        repo = self.make_repository('.')
 
2238
        token = repo.lock_write().repository_token
 
2239
        self.addCleanup(repo.unlock)
 
2240
        request_class = smart_repo.SmartServerRepositoryReconcile
 
2241
        request = request_class(backing)
 
2242
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
2243
            ('ok', ),
 
2244
             'garbage_inventories: 0\n'
 
2245
             'inconsistent_parents: 0\n'),
 
2246
            request.execute('', token))
 
2247
 
 
2248
 
1711
2249
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
1712
2250
 
1713
2251
    def test_is_readonly_no(self):
1751
2289
        self.assertTrue(repo.make_working_trees())
1752
2290
 
1753
2291
 
 
2292
class TestSmartServerRepositoryGetSerializerFormat(
 
2293
    tests.TestCaseWithMemoryTransport):
 
2294
 
 
2295
    def test_get_serializer_format(self):
 
2296
        backing = self.get_transport()
 
2297
        repo = self.make_repository('.', format='2a')
 
2298
        request_class = smart_repo.SmartServerRepositoryGetSerializerFormat
 
2299
        request = request_class(backing)
 
2300
        self.assertEqual(
 
2301
            smart_req.SuccessfulSmartServerResponse(('ok', '10')),
 
2302
            request.execute(''))
 
2303
 
 
2304
 
 
2305
class TestSmartServerRepositoryWriteGroup(
 
2306
    tests.TestCaseWithMemoryTransport):
 
2307
 
 
2308
    def test_start_write_group(self):
 
2309
        backing = self.get_transport()
 
2310
        repo = self.make_repository('.')
 
2311
        lock_token = repo.lock_write().repository_token
 
2312
        self.addCleanup(repo.unlock)
 
2313
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2314
        request = request_class(backing)
 
2315
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
 
2316
            request.execute('', lock_token))
 
2317
 
 
2318
    def test_start_write_group_unsuspendable(self):
 
2319
        backing = self.get_transport()
 
2320
        repo = self.make_repository('.', format='knit')
 
2321
        lock_token = repo.lock_write().repository_token
 
2322
        self.addCleanup(repo.unlock)
 
2323
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2324
        request = request_class(backing)
 
2325
        self.assertEqual(
 
2326
            smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
 
2327
            request.execute('', lock_token))
 
2328
 
 
2329
    def test_commit_write_group(self):
 
2330
        backing = self.get_transport()
 
2331
        repo = self.make_repository('.')
 
2332
        lock_token = repo.lock_write().repository_token
 
2333
        self.addCleanup(repo.unlock)
 
2334
        repo.start_write_group()
 
2335
        tokens = repo.suspend_write_group()
 
2336
        request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
 
2337
        request = request_class(backing)
 
2338
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2339
            request.execute('', lock_token, tokens))
 
2340
 
 
2341
    def test_abort_write_group(self):
 
2342
        backing = self.get_transport()
 
2343
        repo = self.make_repository('.')
 
2344
        lock_token = repo.lock_write().repository_token
 
2345
        repo.start_write_group()
 
2346
        tokens = repo.suspend_write_group()
 
2347
        self.addCleanup(repo.unlock)
 
2348
        request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
 
2349
        request = request_class(backing)
 
2350
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2351
            request.execute('', lock_token, tokens))
 
2352
 
 
2353
    def test_check_write_group(self):
 
2354
        backing = self.get_transport()
 
2355
        repo = self.make_repository('.')
 
2356
        lock_token = repo.lock_write().repository_token
 
2357
        repo.start_write_group()
 
2358
        tokens = repo.suspend_write_group()
 
2359
        self.addCleanup(repo.unlock)
 
2360
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2361
        request = request_class(backing)
 
2362
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2363
            request.execute('', lock_token, tokens))
 
2364
 
 
2365
    def test_check_write_group_invalid(self):
 
2366
        backing = self.get_transport()
 
2367
        repo = self.make_repository('.')
 
2368
        lock_token = repo.lock_write().repository_token
 
2369
        self.addCleanup(repo.unlock)
 
2370
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2371
        request = request_class(backing)
 
2372
        self.assertEqual(smart_req.FailedSmartServerResponse(
 
2373
            ('UnresumableWriteGroup', ['random'],
 
2374
                'Malformed write group token')),
 
2375
            request.execute('', lock_token, ["random"]))
 
2376
 
 
2377
 
1754
2378
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
1755
2379
 
1756
2380
    def make_repo_needing_autopacking(self, path='.'):
1822
2446
        """All registered request_handlers can be found."""
1823
2447
        # If there's a typo in a register_lazy call, this loop will fail with
1824
2448
        # an AttributeError.
1825
 
        for key, item in smart_req.request_handlers.iteritems():
1826
 
            pass
 
2449
        for key in smart_req.request_handlers.keys():
 
2450
            try:
 
2451
                item = smart_req.request_handlers.get(key)
 
2452
            except AttributeError, e:
 
2453
                raise AttributeError('failed to get %s: %s' % (key, e))
1827
2454
 
1828
2455
    def assertHandlerEqual(self, verb, handler):
1829
2456
        self.assertEqual(smart_req.request_handlers.get(verb), handler)
1830
2457
 
1831
2458
    def test_registered_methods(self):
1832
2459
        """Test that known methods are registered to the correct object."""
 
2460
        self.assertHandlerEqual('Branch.break_lock',
 
2461
            smart_branch.SmartServerBranchBreakLock)
1833
2462
        self.assertHandlerEqual('Branch.get_config_file',
1834
2463
            smart_branch.SmartServerBranchGetConfigFile)
 
2464
        self.assertHandlerEqual('Branch.put_config_file',
 
2465
            smart_branch.SmartServerBranchPutConfigFile)
1835
2466
        self.assertHandlerEqual('Branch.get_parent',
1836
2467
            smart_branch.SmartServerBranchGetParent)
 
2468
        self.assertHandlerEqual('Branch.get_physical_lock_status',
 
2469
            smart_branch.SmartServerBranchRequestGetPhysicalLockStatus)
1837
2470
        self.assertHandlerEqual('Branch.get_tags_bytes',
1838
2471
            smart_branch.SmartServerBranchGetTagsBytes)
1839
2472
        self.assertHandlerEqual('Branch.lock_write',
1842
2475
            smart_branch.SmartServerBranchRequestLastRevisionInfo)
1843
2476
        self.assertHandlerEqual('Branch.revision_history',
1844
2477
            smart_branch.SmartServerRequestRevisionHistory)
 
2478
        self.assertHandlerEqual('Branch.revision_id_to_revno',
 
2479
            smart_branch.SmartServerBranchRequestRevisionIdToRevno)
1845
2480
        self.assertHandlerEqual('Branch.set_config_option',
1846
2481
            smart_branch.SmartServerBranchRequestSetConfigOption)
1847
2482
        self.assertHandlerEqual('Branch.set_last_revision',
1854
2489
            smart_branch.SmartServerBranchRequestSetParentLocation)
1855
2490
        self.assertHandlerEqual('Branch.unlock',
1856
2491
            smart_branch.SmartServerBranchRequestUnlock)
 
2492
        self.assertHandlerEqual('BzrDir.destroy_branch',
 
2493
            smart_dir.SmartServerBzrDirRequestDestroyBranch)
1857
2494
        self.assertHandlerEqual('BzrDir.find_repository',
1858
2495
            smart_dir.SmartServerRequestFindRepositoryV1)
1859
2496
        self.assertHandlerEqual('BzrDir.find_repositoryV2',
1862
2499
            smart_dir.SmartServerRequestInitializeBzrDir)
1863
2500
        self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
1864
2501
            smart_dir.SmartServerRequestBzrDirInitializeEx)
 
2502
        self.assertHandlerEqual('BzrDir.checkout_metadir',
 
2503
            smart_dir.SmartServerBzrDirRequestCheckoutMetaDir)
1865
2504
        self.assertHandlerEqual('BzrDir.cloning_metadir',
1866
2505
            smart_dir.SmartServerBzrDirRequestCloningMetaDir)
1867
2506
        self.assertHandlerEqual('BzrDir.get_config_file',
1874
2513
            smart_dir.SmartServerRequestOpenBranchV3)
1875
2514
        self.assertHandlerEqual('PackRepository.autopack',
1876
2515
            smart_packrepo.SmartServerPackRepositoryAutopack)
 
2516
        self.assertHandlerEqual('Repository.add_signature_text',
 
2517
            smart_repo.SmartServerRepositoryAddSignatureText)
 
2518
        self.assertHandlerEqual('Repository.all_revision_ids',
 
2519
            smart_repo.SmartServerRepositoryAllRevisionIds)
 
2520
        self.assertHandlerEqual('Repository.break_lock',
 
2521
            smart_repo.SmartServerRepositoryBreakLock)
1877
2522
        self.assertHandlerEqual('Repository.gather_stats',
1878
2523
            smart_repo.SmartServerRepositoryGatherStats)
1879
2524
        self.assertHandlerEqual('Repository.get_parent_map',
1880
2525
            smart_repo.SmartServerRepositoryGetParentMap)
 
2526
        self.assertHandlerEqual('Repository.get_physical_lock_status',
 
2527
            smart_repo.SmartServerRepositoryGetPhysicalLockStatus)
1881
2528
        self.assertHandlerEqual('Repository.get_rev_id_for_revno',
1882
2529
            smart_repo.SmartServerRepositoryGetRevIdForRevno)
1883
2530
        self.assertHandlerEqual('Repository.get_revision_graph',
1884
2531
            smart_repo.SmartServerRepositoryGetRevisionGraph)
 
2532
        self.assertHandlerEqual('Repository.get_revision_signature_text',
 
2533
            smart_repo.SmartServerRepositoryGetRevisionSignatureText)
1885
2534
        self.assertHandlerEqual('Repository.get_stream',
1886
2535
            smart_repo.SmartServerRepositoryGetStream)
 
2536
        self.assertHandlerEqual('Repository.get_stream_1.19',
 
2537
            smart_repo.SmartServerRepositoryGetStream_1_19)
 
2538
        self.assertHandlerEqual('Repository.iter_revisions',
 
2539
            smart_repo.SmartServerRepositoryIterRevisions)
1887
2540
        self.assertHandlerEqual('Repository.has_revision',
1888
2541
            smart_repo.SmartServerRequestHasRevision)
1889
2542
        self.assertHandlerEqual('Repository.insert_stream',
1892
2545
            smart_repo.SmartServerRepositoryInsertStreamLocked)
1893
2546
        self.assertHandlerEqual('Repository.is_shared',
1894
2547
            smart_repo.SmartServerRepositoryIsShared)
 
2548
        self.assertHandlerEqual('Repository.iter_files_bytes',
 
2549
            smart_repo.SmartServerRepositoryIterFilesBytes)
1895
2550
        self.assertHandlerEqual('Repository.lock_write',
1896
2551
            smart_repo.SmartServerRepositoryLockWrite)
 
2552
        self.assertHandlerEqual('Repository.make_working_trees',
 
2553
            smart_repo.SmartServerRepositoryMakeWorkingTrees)
 
2554
        self.assertHandlerEqual('Repository.pack',
 
2555
            smart_repo.SmartServerRepositoryPack)
 
2556
        self.assertHandlerEqual('Repository.reconcile',
 
2557
            smart_repo.SmartServerRepositoryReconcile)
1897
2558
        self.assertHandlerEqual('Repository.tarball',
1898
2559
            smart_repo.SmartServerRepositoryTarball)
1899
2560
        self.assertHandlerEqual('Repository.unlock',
1900
2561
            smart_repo.SmartServerRepositoryUnlock)
 
2562
        self.assertHandlerEqual('Repository.start_write_group',
 
2563
            smart_repo.SmartServerRepositoryStartWriteGroup)
 
2564
        self.assertHandlerEqual('Repository.check_write_group',
 
2565
            smart_repo.SmartServerRepositoryCheckWriteGroup)
 
2566
        self.assertHandlerEqual('Repository.commit_write_group',
 
2567
            smart_repo.SmartServerRepositoryCommitWriteGroup)
 
2568
        self.assertHandlerEqual('Repository.abort_write_group',
 
2569
            smart_repo.SmartServerRepositoryAbortWriteGroup)
 
2570
        self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
 
2571
            smart_repo.SmartServerRepositoryGetSerializerFormat)
 
2572
        self.assertHandlerEqual('VersionedFileRepository.get_inventories',
 
2573
            smart_repo.SmartServerRepositoryGetInventories)
1901
2574
        self.assertHandlerEqual('Transport.is_readonly',
1902
2575
            smart_req.SmartServerIsReadonly)
 
2576
 
 
2577
 
 
2578
class SmartTCPServerHookTests(tests.TestCaseWithMemoryTransport):
 
2579
    """Tests for SmartTCPServer hooks."""
 
2580
 
 
2581
    def setUp(self):
 
2582
        super(SmartTCPServerHookTests, self).setUp()
 
2583
        self.server = server.SmartTCPServer(self.get_transport())
 
2584
 
 
2585
    def test_run_server_started_hooks(self):
 
2586
        """Test the server started hooks get fired properly."""
 
2587
        started_calls = []
 
2588
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2589
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2590
            None)
 
2591
        started_ex_calls = []
 
2592
        server.SmartTCPServer.hooks.install_named_hook('server_started_ex',
 
2593
            lambda backing_urls, url: started_ex_calls.append((backing_urls, url)),
 
2594
            None)
 
2595
        self.server._sockname = ('example.com', 42)
 
2596
        self.server.run_server_started_hooks()
 
2597
        self.assertEquals(started_calls,
 
2598
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2599
        self.assertEquals(started_ex_calls,
 
2600
            [([self.get_transport().base], self.server)])
 
2601
 
 
2602
    def test_run_server_started_hooks_ipv6(self):
 
2603
        """Test that socknames can contain 4-tuples."""
 
2604
        self.server._sockname = ('::', 42, 0, 0)
 
2605
        started_calls = []
 
2606
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2607
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2608
            None)
 
2609
        self.server.run_server_started_hooks()
 
2610
        self.assertEquals(started_calls,
 
2611
                [([self.get_transport().base], 'bzr://:::42/')])
 
2612
 
 
2613
    def test_run_server_stopped_hooks(self):
 
2614
        """Test the server stopped hooks."""
 
2615
        self.server._sockname = ('example.com', 42)
 
2616
        stopped_calls = []
 
2617
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
 
2618
            lambda backing_urls, url: stopped_calls.append((backing_urls, url)),
 
2619
            None)
 
2620
        self.server.run_server_stopped_hooks()
 
2621
        self.assertEquals(stopped_calls,
 
2622
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2623
 
 
2624
 
 
2625
class TestSmartServerRepositoryPack(tests.TestCaseWithMemoryTransport):
 
2626
 
 
2627
    def test_pack(self):
 
2628
        backing = self.get_transport()
 
2629
        request = smart_repo.SmartServerRepositoryPack(backing)
 
2630
        tree = self.make_branch_and_memory_tree('.')
 
2631
        repo_token = tree.branch.repository.lock_write().repository_token
 
2632
 
 
2633
        self.assertIs(None, request.execute('', repo_token, False))
 
2634
 
 
2635
        self.assertEqual(
 
2636
            smart_req.SuccessfulSmartServerResponse(('ok', ), ),
 
2637
            request.do_body(''))
 
2638
 
 
2639
 
 
2640
class TestSmartServerRepositoryGetInventories(tests.TestCaseWithTransport):
 
2641
 
 
2642
    def _get_serialized_inventory_delta(self, repository, base_revid, revid):
 
2643
        base_inv = repository.revision_tree(base_revid).inventory
 
2644
        inv = repository.revision_tree(revid).inventory
 
2645
        inv_delta = inv._make_delta(base_inv)
 
2646
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
2647
        return "".join(serializer.delta_to_lines(base_revid, revid, inv_delta))
 
2648
 
 
2649
    def test_single(self):
 
2650
        backing = self.get_transport()
 
2651
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2652
        t = self.make_branch_and_tree('.', format='2a')
 
2653
        self.addCleanup(t.lock_write().unlock)
 
2654
        self.build_tree_contents([("file", "somecontents")])
 
2655
        t.add(["file"], ["thefileid"])
 
2656
        t.commit(rev_id='somerev', message="add file")
 
2657
        self.assertIs(None, request.execute('', 'unordered'))
 
2658
        response = request.do_body("somerev\n")
 
2659
        self.assertTrue(response.is_successful())
 
2660
        self.assertEquals(response.args, ("ok", ))
 
2661
        stream = [('inventory-deltas', [
 
2662
            versionedfile.FulltextContentFactory('somerev', None, None,
 
2663
                self._get_serialized_inventory_delta(
 
2664
                    t.branch.repository, 'null:', 'somerev'))])]
 
2665
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
2666
        self.assertEquals(
 
2667
            "".join(response.body_stream),
 
2668
            "".join(smart_repo._stream_to_byte_stream(stream, fmt)))
 
2669
 
 
2670
    def test_empty(self):
 
2671
        backing = self.get_transport()
 
2672
        request = smart_repo.SmartServerRepositoryGetInventories(backing)
 
2673
        t = self.make_branch_and_tree('.', format='2a')
 
2674
        self.addCleanup(t.lock_write().unlock)
 
2675
        self.build_tree_contents([("file", "somecontents")])
 
2676
        t.add(["file"], ["thefileid"])
 
2677
        t.commit(rev_id='somerev', message="add file")
 
2678
        self.assertIs(None, request.execute('', 'unordered'))
 
2679
        response = request.do_body("")
 
2680
        self.assertTrue(response.is_successful())
 
2681
        self.assertEquals(response.args, ("ok", ))
 
2682
        self.assertEquals("".join(response.body_stream),
 
2683
            "Bazaar pack format 1 (introduced in 0.18)\nB54\n\nBazaar repository format 2a (needs bzr 1.16 or later)\nE")