~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-03-06 06:48:25 UTC
  • mfrom: (4070.8.6 debug-config)
  • Revision ID: pqm@pqm.ubuntu.com-20090306064825-kbpwggw21dygeix6
(mbp) debug_flags configuration option

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Tests for remote bzrdir/branch/repo/etc
18
18
 
36
36
    repository,
37
37
    smart,
38
38
    tests,
39
 
    treebuilder,
40
39
    urlutils,
41
40
    )
42
41
from bzrlib.branch import Branch
43
42
from bzrlib.bzrdir import BzrDir, BzrDirFormat
44
43
from bzrlib.remote import (
45
44
    RemoteBranch,
46
 
    RemoteBranchFormat,
47
45
    RemoteBzrDir,
48
46
    RemoteBzrDirFormat,
49
47
    RemoteRepository,
50
 
    RemoteRepositoryFormat,
51
48
    )
52
 
from bzrlib.repofmt import pack_repo
53
49
from bzrlib.revision import NULL_REVISION
54
50
from bzrlib.smart import server, medium
55
51
from bzrlib.smart.client import _SmartClient
56
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
57
 
from bzrlib.tests import (
58
 
    condition_isinstance,
59
 
    split_suite_by_condition,
60
 
    multiply_tests,
61
 
    )
 
52
from bzrlib.symbol_versioning import one_four
62
53
from bzrlib.transport import get_transport, http
63
54
from bzrlib.transport.memory import MemoryTransport
64
55
from bzrlib.transport.remote import (
67
58
    RemoteTCPTransport,
68
59
)
69
60
 
70
 
def load_tests(standard_tests, module, loader):
71
 
    to_adapt, result = split_suite_by_condition(
72
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
73
 
    smart_server_version_scenarios = [
74
 
        ('HPSS-v2',
75
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
76
 
        ('HPSS-v3',
77
 
            {'transport_server': server.SmartTCPServer_for_testing})]
78
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
79
 
 
80
61
 
81
62
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
82
63
 
83
64
    def setUp(self):
 
65
        self.transport_server = server.SmartTCPServer_for_testing
84
66
        super(BasicRemoteObjectTests, self).setUp()
85
67
        self.transport = self.get_transport()
86
68
        # make a branch that can be opened over the smart transport
131
113
        b = BzrDir.open_from_transport(self.transport).open_branch()
132
114
        self.assertStartsWith(str(b), 'RemoteBranch(')
133
115
 
134
 
    def test_remote_branch_format_supports_stacking(self):
135
 
        t = self.transport
136
 
        self.make_branch('unstackable', format='pack-0.92')
137
 
        b = BzrDir.open_from_transport(t.clone('unstackable')).open_branch()
138
 
        self.assertFalse(b._format.supports_stacking())
139
 
        self.make_branch('stackable', format='1.9')
140
 
        b = BzrDir.open_from_transport(t.clone('stackable')).open_branch()
141
 
        self.assertTrue(b._format.supports_stacking())
142
 
 
143
 
    def test_remote_repo_format_supports_external_references(self):
144
 
        t = self.transport
145
 
        bd = self.make_bzrdir('unstackable', format='pack-0.92')
146
 
        r = bd.create_repository()
147
 
        self.assertFalse(r._format.supports_external_lookups)
148
 
        r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
149
 
        self.assertFalse(r._format.supports_external_lookups)
150
 
        bd = self.make_bzrdir('stackable', format='1.9')
151
 
        r = bd.create_repository()
152
 
        self.assertTrue(r._format.supports_external_lookups)
153
 
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
154
 
        self.assertTrue(r._format.supports_external_lookups)
155
 
 
156
116
 
157
117
class FakeProtocol(object):
158
118
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
273
233
        stream = list(stream)
274
234
        self._check_call(args[0], args[1:])
275
235
        self._calls.append(('call_with_body_stream', args[0], args[1:], stream))
276
 
        result = self._get_next_response()
277
 
        # The second value returned from call_with_body_stream is supposed to
278
 
        # be a response_handler object, but so far no tests depend on that.
279
 
        response_handler = None 
280
 
        return result[1], response_handler
 
236
        return self._get_next_response()[1]
281
237
 
282
238
 
283
239
class FakeMedium(medium.SmartClientMedium):
306
262
 
307
263
class TestRemote(tests.TestCaseWithMemoryTransport):
308
264
 
309
 
    def get_branch_format(self):
310
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
311
 
        return reference_bzrdir_format.get_branch_format()
312
 
 
313
265
    def get_repo_format(self):
314
266
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
315
267
        return reference_bzrdir_format.repository_format
410
362
            call.call.method == verb])
411
363
        self.assertEqual(1, call_count)
412
364
 
413
 
    def test_branch_reference(self):
414
 
        transport = self.get_transport('quack')
415
 
        referenced = self.make_branch('referenced')
416
 
        expected = referenced.bzrdir.cloning_metadir()
417
 
        client = FakeClient(transport.base)
418
 
        client.add_expected_call(
419
 
            'BzrDir.cloning_metadir', ('quack/', 'False'),
420
 
            'error', ('BranchReference',)),
421
 
        client.add_expected_call(
422
 
            'BzrDir.open_branchV2', ('quack/',),
423
 
            'success', ('ref', self.get_url('referenced'))),
424
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
425
 
            _client=client)
426
 
        result = a_bzrdir.cloning_metadir()
427
 
        # We should have got a control dir matching the referenced branch.
428
 
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
429
 
        self.assertEqual(expected._repository_format, result._repository_format)
430
 
        self.assertEqual(expected._branch_format, result._branch_format)
431
 
        client.finished_test()
432
 
 
433
365
    def test_current_server(self):
434
366
        transport = self.get_transport('.')
435
367
        transport = transport.clone('quack')
439
371
        control_name = reference_bzrdir_format.network_name()
440
372
        client.add_expected_call(
441
373
            'BzrDir.cloning_metadir', ('quack/', 'False'),
442
 
            'success', (control_name, '', ('branch', ''))),
 
374
            'success', (control_name, '', ('direct', ''))),
443
375
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
444
376
            _client=client)
445
377
        result = a_bzrdir.cloning_metadir()
454
386
 
455
387
class TestBzrDirOpenBranch(TestRemote):
456
388
 
457
 
    def test_backwards_compat(self):
458
 
        self.setup_smart_server_with_call_log()
459
 
        self.make_branch('.')
460
 
        a_dir = BzrDir.open(self.get_url('.'))
461
 
        self.reset_smart_call_log()
462
 
        verb = 'BzrDir.open_branchV2'
463
 
        self.disable_verb(verb)
464
 
        format = a_dir.open_branch()
465
 
        call_count = len([call for call in self.hpss_calls if
466
 
            call.call.method == verb])
467
 
        self.assertEqual(1, call_count)
468
 
 
469
389
    def test_branch_present(self):
470
390
        reference_format = self.get_repo_format()
471
391
        network_name = reference_format.network_name()
472
 
        branch_network_name = self.get_branch_format().network_name()
473
392
        transport = MemoryTransport()
474
393
        transport.mkdir('quack')
475
394
        transport = transport.clone('quack')
476
395
        client = FakeClient(transport.base)
477
396
        client.add_expected_call(
478
 
            'BzrDir.open_branchV2', ('quack/',),
479
 
            'success', ('branch', branch_network_name))
 
397
            'BzrDir.open_branch', ('quack/',),
 
398
            'success', ('ok', ''))
480
399
        client.add_expected_call(
481
400
            'BzrDir.find_repositoryV3', ('quack/',),
482
401
            'success', ('ok', '', 'no', 'no', 'no', network_name))
500
419
            _client=client)
501
420
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
502
421
        self.assertEqual(
503
 
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
 
422
            [('call', 'BzrDir.open_branch', ('quack/',))],
504
423
            client._calls)
505
424
 
506
425
    def test__get_tree_branch(self):
528
447
        client = FakeClient(transport.base)
529
448
        reference_format = self.get_repo_format()
530
449
        network_name = reference_format.network_name()
531
 
        branch_network_name = self.get_branch_format().network_name()
532
450
        client.add_expected_call(
533
 
            'BzrDir.open_branchV2', ('~hello/',),
534
 
            'success', ('branch', branch_network_name))
 
451
            'BzrDir.open_branch', ('~hello/',),
 
452
            'success', ('ok', ''))
535
453
        client.add_expected_call(
536
454
            'BzrDir.find_repositoryV3', ('~hello/',),
537
455
            'success', ('ok', '', 'no', 'no', 'no', network_name))
769
687
        return OldSmartClient()
770
688
 
771
689
 
772
 
class RemoteBranchTestCase(TestRemote):
 
690
class RemoteBranchTestCase(tests.TestCase):
773
691
 
774
692
    def make_remote_branch(self, transport, client):
775
693
        """Make a RemoteBranch using 'client' as its _SmartClient.
783
701
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
784
702
            _client=False)
785
703
        repo = RemoteRepository(bzrdir, None, _client=client)
786
 
        branch_format = self.get_branch_format()
787
 
        format = RemoteBranchFormat(network_name=branch_format.network_name())
788
 
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
 
704
        return RemoteBranch(bzrdir, repo, _client=client)
789
705
 
790
706
 
791
707
class TestBranchGetParent(RemoteBranchTestCase):
838
754
        self.assertEqual('http://foo/', result)
839
755
 
840
756
 
841
 
class TestBranchGetTagsBytes(RemoteBranchTestCase):
842
 
 
843
 
    def test_backwards_compat(self):
844
 
        self.setup_smart_server_with_call_log()
845
 
        branch = self.make_branch('.')
846
 
        self.reset_smart_call_log()
847
 
        verb = 'Branch.get_tags_bytes'
848
 
        self.disable_verb(verb)
849
 
        branch.tags.get_tag_dict()
850
 
        call_count = len([call for call in self.hpss_calls if
851
 
            call.call.method == verb])
852
 
        self.assertEqual(1, call_count)
853
 
 
854
 
    def test_trivial(self):
855
 
        transport = MemoryTransport()
856
 
        client = FakeClient(transport.base)
857
 
        client.add_expected_call(
858
 
            'Branch.get_stacked_on_url', ('quack/',),
859
 
            'error', ('NotStacked',))
860
 
        client.add_expected_call(
861
 
            'Branch.get_tags_bytes', ('quack/',),
862
 
            'success', ('',))
863
 
        transport.mkdir('quack')
864
 
        transport = transport.clone('quack')
865
 
        branch = self.make_remote_branch(transport, client)
866
 
        result = branch.tags.get_tag_dict()
867
 
        client.finished_test()
868
 
        self.assertEqual({}, result)
869
 
 
870
 
 
871
757
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
872
758
 
873
759
    def test_empty_branch(self):
930
816
            'success', ('ok', vfs_url))
931
817
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
932
818
            _client=client)
933
 
        repo_fmt = remote.RemoteRepositoryFormat()
934
 
        repo_fmt._custom_format = stacked_branch.repository._format
935
 
        branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
 
819
        branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, None),
936
820
            _client=client)
937
821
        result = branch.get_stacked_on_url()
938
822
        self.assertEqual(vfs_url, result)
943
827
        stacked_branch = self.make_branch('stacked', format='1.6')
944
828
        stacked_branch.set_stacked_on_url('../base')
945
829
        client = FakeClient(self.get_url())
946
 
        branch_network_name = self.get_branch_format().network_name()
947
830
        client.add_expected_call(
948
 
            'BzrDir.open_branchV2', ('stacked/',),
949
 
            'success', ('branch', branch_network_name))
 
831
            'BzrDir.open_branch', ('stacked/',),
 
832
            'success', ('ok', ''))
950
833
        client.add_expected_call(
951
834
            'BzrDir.find_repositoryV3', ('stacked/',),
952
 
            'success', ('ok', '', 'no', 'no', 'yes',
 
835
            'success', ('ok', '', 'no', 'no', 'no',
953
836
                stacked_branch.repository._format.network_name()))
954
837
        # called twice, once from constructor and then again by us
955
838
        client.add_expected_call(
979
862
        reference_format = self.get_repo_format()
980
863
        network_name = reference_format.network_name()
981
864
        client = FakeClient(self.get_url())
982
 
        branch_network_name = self.get_branch_format().network_name()
983
865
        client.add_expected_call(
984
 
            'BzrDir.open_branchV2', ('stacked/',),
985
 
            'success', ('branch', branch_network_name))
 
866
            'BzrDir.open_branch', ('stacked/',),
 
867
            'success', ('ok', ''))
986
868
        client.add_expected_call(
987
869
            'BzrDir.find_repositoryV3', ('stacked/',),
988
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
870
            'success', ('ok', '', 'no', 'no', 'no', network_name))
989
871
        # called twice, once from constructor and then again by us
990
872
        client.add_expected_call(
991
873
            'Branch.get_stacked_on_url', ('stacked/',),
999
881
        result = branch.get_stacked_on_url()
1000
882
        self.assertEqual('../base', result)
1001
883
        client.finished_test()
1002
 
        # it's in the fallback list both for the RemoteRepository.
 
884
        # it's in the fallback list both for the RemoteRepository and its vfs
 
885
        # repository
1003
886
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1004
 
        # And we haven't had to construct a real repository.
1005
 
        self.assertEqual(None, branch.repository._real_repository)
 
887
        self.assertEqual(1,
 
888
            len(branch.repository._real_repository._fallback_repositories))
1006
889
 
1007
890
 
1008
891
class TestBranchSetLastRevision(RemoteBranchTestCase):
1332
1215
        self.assertEqual('rejection message', err.msg)
1333
1216
 
1334
1217
 
1335
 
class TestBranchGetSetConfig(RemoteBranchTestCase):
 
1218
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
 
1219
    """Getting the branch configuration should use an abstract method not vfs.
 
1220
    """
1336
1221
 
1337
1222
    def test_get_branch_conf(self):
1338
 
        # in an empty branch we decode the response properly
1339
 
        client = FakeClient()
1340
 
        client.add_expected_call(
1341
 
            'Branch.get_stacked_on_url', ('memory:///',),
1342
 
            'error', ('NotStacked',),)
1343
 
        client.add_success_response_with_body('# config file body', 'ok')
1344
 
        transport = MemoryTransport()
1345
 
        branch = self.make_remote_branch(transport, client)
1346
 
        config = branch.get_config()
1347
 
        config.has_explicit_nickname()
1348
 
        self.assertEqual(
1349
 
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1350
 
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1351
 
            client._calls)
1352
 
 
1353
 
    def test_get_multi_line_branch_conf(self):
1354
 
        # Make sure that multiple-line branch.conf files are supported
1355
 
        #
1356
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1357
 
        client = FakeClient()
1358
 
        client.add_expected_call(
1359
 
            'Branch.get_stacked_on_url', ('memory:///',),
1360
 
            'error', ('NotStacked',),)
1361
 
        client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
1362
 
        transport = MemoryTransport()
1363
 
        branch = self.make_remote_branch(transport, client)
1364
 
        config = branch.get_config()
1365
 
        self.assertEqual(u'2', config.get_user_option('b'))
1366
 
 
1367
 
    def test_set_option(self):
1368
 
        client = FakeClient()
1369
 
        client.add_expected_call(
1370
 
            'Branch.get_stacked_on_url', ('memory:///',),
1371
 
            'error', ('NotStacked',),)
1372
 
        client.add_expected_call(
1373
 
            'Branch.lock_write', ('memory:///', '', ''),
1374
 
            'success', ('ok', 'branch token', 'repo token'))
1375
 
        client.add_expected_call(
1376
 
            'Branch.set_config_option', ('memory:///', 'branch token',
1377
 
            'repo token', 'foo', 'bar', ''),
1378
 
            'success', ())
1379
 
        client.add_expected_call(
1380
 
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1381
 
            'success', ('ok',))
1382
 
        transport = MemoryTransport()
1383
 
        branch = self.make_remote_branch(transport, client)
1384
 
        branch.lock_write()
1385
 
        config = branch._get_config()
1386
 
        config.set_option('foo', 'bar')
1387
 
        branch.unlock()
1388
 
        client.finished_test()
1389
 
 
1390
 
    def test_backwards_compat_set_option(self):
1391
 
        self.setup_smart_server_with_call_log()
1392
 
        branch = self.make_branch('.')
1393
 
        verb = 'Branch.set_config_option'
1394
 
        self.disable_verb(verb)
1395
 
        branch.lock_write()
1396
 
        self.addCleanup(branch.unlock)
1397
 
        self.reset_smart_call_log()
1398
 
        branch._get_config().set_option('value', 'name')
1399
 
        self.assertLength(10, self.hpss_calls)
1400
 
        self.assertEqual('value', branch._get_config().get_option('name'))
 
1223
        raise tests.KnownFailure('branch.conf is not retrieved by get_config_file')
 
1224
        ## # We should see that branch.get_config() does a single rpc to get the
 
1225
        ## # remote configuration file, abstracting away where that is stored on
 
1226
        ## # the server.  However at the moment it always falls back to using the
 
1227
        ## # vfs, and this would need some changes in config.py.
 
1228
 
 
1229
        ## # in an empty branch we decode the response properly
 
1230
        ## client = FakeClient([(('ok', ), '# config file body')], self.get_url())
 
1231
        ## # we need to make a real branch because the remote_branch.control_files
 
1232
        ## # will trigger _ensure_real.
 
1233
        ## branch = self.make_branch('quack')
 
1234
        ## transport = branch.bzrdir.root_transport
 
1235
        ## # we do not want bzrdir to make any remote calls
 
1236
        ## bzrdir = RemoteBzrDir(transport, _client=False)
 
1237
        ## branch = RemoteBranch(bzrdir, None, _client=client)
 
1238
        ## config = branch.get_config()
 
1239
        ## self.assertEqual(
 
1240
        ##     [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
 
1241
        ##     client._calls)
1401
1242
 
1402
1243
 
1403
1244
class TestBranchLockWrite(RemoteBranchTestCase):
1514
1355
        return repo, client
1515
1356
 
1516
1357
 
1517
 
class TestRepositoryFormat(TestRemoteRepository):
1518
 
 
1519
 
    def test_fast_delta(self):
1520
 
        true_name = pack_repo.RepositoryFormatPackDevelopment2().network_name()
1521
 
        true_format = RemoteRepositoryFormat()
1522
 
        true_format._network_name = true_name
1523
 
        self.assertEqual(True, true_format.fast_deltas)
1524
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
1525
 
        false_format = RemoteRepositoryFormat()
1526
 
        false_format._network_name = false_name
1527
 
        self.assertEqual(False, false_format.fast_deltas)
1528
 
 
1529
 
 
1530
1358
class TestRepositoryGatherStats(TestRemoteRepository):
1531
1359
 
1532
1360
    def test_revid_none(self):
1620
1448
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
1621
1449
        self.assertEqual(
1622
1450
            [('call_with_body_bytes_expecting_body',
1623
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1624
 
              '\n\n0')],
 
1451
              'Repository.get_parent_map', ('quack/', r2), '\n\n0')],
1625
1452
            client._calls)
1626
1453
        repo.unlock()
1627
1454
        # now we call again, and it should use the second response.
1631
1458
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
1632
1459
        self.assertEqual(
1633
1460
            [('call_with_body_bytes_expecting_body',
1634
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1635
 
              '\n\n0'),
 
1461
              'Repository.get_parent_map', ('quack/', r2), '\n\n0'),
1636
1462
             ('call_with_body_bytes_expecting_body',
1637
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r1),
1638
 
              '\n\n0'),
 
1463
              'Repository.get_parent_map', ('quack/', r1), '\n\n0'),
1639
1464
            ],
1640
1465
            client._calls)
1641
1466
        repo.unlock()
1642
1467
 
1643
1468
    def test_get_parent_map_reconnects_if_unknown_method(self):
1644
1469
        transport_path = 'quack'
1645
 
        rev_id = 'revision-id'
1646
1470
        repo, client = self.setup_fake_client_and_repository(transport_path)
1647
 
        client.add_unknown_method_response('Repository.get_parent_map')
1648
 
        client.add_success_response_with_body(rev_id, 'ok')
 
1471
        client.add_unknown_method_response('Repository,get_parent_map')
 
1472
        client.add_success_response_with_body('', 'ok')
1649
1473
        self.assertFalse(client._medium._is_remote_before((1, 2)))
1650
 
        parents = repo.get_parent_map([rev_id])
 
1474
        rev_id = 'revision-id'
 
1475
        expected_deprecations = [
 
1476
            'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
 
1477
            'in version 1.4.']
 
1478
        parents = self.callDeprecated(
 
1479
            expected_deprecations, repo.get_parent_map, [rev_id])
1651
1480
        self.assertEqual(
1652
1481
            [('call_with_body_bytes_expecting_body',
1653
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1654
 
              rev_id), '\n\n0'),
 
1482
              'Repository.get_parent_map', ('quack/', rev_id), '\n\n0'),
1655
1483
             ('disconnect medium',),
1656
1484
             ('call_expecting_body', 'Repository.get_revision_graph',
1657
1485
              ('quack/', ''))],
1658
1486
            client._calls)
1659
1487
        # The medium is now marked as being connected to an older server
1660
1488
        self.assertTrue(client._medium._is_remote_before((1, 2)))
1661
 
        self.assertEqual({rev_id: ('null:',)}, parents)
1662
1489
 
1663
1490
    def test_get_parent_map_fallback_parentless_node(self):
1664
1491
        """get_parent_map falls back to get_revision_graph on old servers.  The
1676
1503
        repo, client = self.setup_fake_client_and_repository(transport_path)
1677
1504
        client.add_success_response_with_body(rev_id, 'ok')
1678
1505
        client._medium._remember_remote_is_before((1, 2))
1679
 
        parents = repo.get_parent_map([rev_id])
 
1506
        expected_deprecations = [
 
1507
            'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
 
1508
            'in version 1.4.']
 
1509
        parents = self.callDeprecated(
 
1510
            expected_deprecations, repo.get_parent_map, [rev_id])
1680
1511
        self.assertEqual(
1681
1512
            [('call_expecting_body', 'Repository.get_revision_graph',
1682
1513
             ('quack/', ''))],
1690
1521
            errors.UnexpectedSmartServerResponse,
1691
1522
            repo.get_parent_map, ['a-revision-id'])
1692
1523
 
1693
 
    def test_get_parent_map_negative_caches_missing_keys(self):
1694
 
        self.setup_smart_server_with_call_log()
1695
 
        repo = self.make_repository('foo')
1696
 
        self.assertIsInstance(repo, RemoteRepository)
1697
 
        repo.lock_read()
1698
 
        self.addCleanup(repo.unlock)
1699
 
        self.reset_smart_call_log()
1700
 
        graph = repo.get_graph()
1701
 
        self.assertEqual({},
1702
 
            graph.get_parent_map(['some-missing', 'other-missing']))
1703
 
        self.assertLength(1, self.hpss_calls)
1704
 
        # No call if we repeat this
1705
 
        self.reset_smart_call_log()
1706
 
        graph = repo.get_graph()
1707
 
        self.assertEqual({},
1708
 
            graph.get_parent_map(['some-missing', 'other-missing']))
1709
 
        self.assertLength(0, self.hpss_calls)
1710
 
        # Asking for more unknown keys makes a request.
1711
 
        self.reset_smart_call_log()
1712
 
        graph = repo.get_graph()
1713
 
        self.assertEqual({},
1714
 
            graph.get_parent_map(['some-missing', 'other-missing',
1715
 
                'more-missing']))
1716
 
        self.assertLength(1, self.hpss_calls)
1717
 
 
1718
 
    def disableExtraResults(self):
1719
 
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
1720
 
        SmartServerRepositoryGetParentMap.no_extra_results = True
1721
 
        def reset_values():
1722
 
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
1723
 
        self.addCleanup(reset_values)
1724
 
 
1725
 
    def test_null_cached_missing_and_stop_key(self):
1726
 
        self.setup_smart_server_with_call_log()
1727
 
        # Make a branch with a single revision.
1728
 
        builder = self.make_branch_builder('foo')
1729
 
        builder.start_series()
1730
 
        builder.build_snapshot('first', None, [
1731
 
            ('add', ('', 'root-id', 'directory', ''))])
1732
 
        builder.finish_series()
1733
 
        branch = builder.get_branch()
1734
 
        repo = branch.repository
1735
 
        self.assertIsInstance(repo, RemoteRepository)
1736
 
        # Stop the server from sending extra results.
1737
 
        self.disableExtraResults()
1738
 
        repo.lock_read()
1739
 
        self.addCleanup(repo.unlock)
1740
 
        self.reset_smart_call_log()
1741
 
        graph = repo.get_graph()
1742
 
        # Query for 'first' and 'null:'.  Because 'null:' is a parent of
1743
 
        # 'first' it will be a candidate for the stop_keys of subsequent
1744
 
        # requests, and because 'null:' was queried but not returned it will be
1745
 
        # cached as missing.
1746
 
        self.assertEqual({'first': ('null:',)},
1747
 
            graph.get_parent_map(['first', 'null:']))
1748
 
        # Now query for another key.  This request will pass along a recipe of
1749
 
        # start and stop keys describing the already cached results, and this
1750
 
        # recipe's revision count must be correct (or else it will trigger an
1751
 
        # error from the server).
1752
 
        self.assertEqual({}, graph.get_parent_map(['another-key']))
1753
 
        # This assertion guards against disableExtraResults silently failing to
1754
 
        # work, thus invalidating the test.
1755
 
        self.assertLength(2, self.hpss_calls)
1756
 
 
1757
 
    def test_get_parent_map_gets_ghosts_from_result(self):
1758
 
        # asking for a revision should negatively cache close ghosts in its
1759
 
        # ancestry.
1760
 
        self.setup_smart_server_with_call_log()
1761
 
        tree = self.make_branch_and_memory_tree('foo')
1762
 
        tree.lock_write()
1763
 
        try:
1764
 
            builder = treebuilder.TreeBuilder()
1765
 
            builder.start_tree(tree)
1766
 
            builder.build([])
1767
 
            builder.finish_tree()
1768
 
            tree.set_parent_ids(['non-existant'], allow_leftmost_as_ghost=True)
1769
 
            rev_id = tree.commit('')
1770
 
        finally:
1771
 
            tree.unlock()
1772
 
        tree.lock_read()
1773
 
        self.addCleanup(tree.unlock)
1774
 
        repo = tree.branch.repository
1775
 
        self.assertIsInstance(repo, RemoteRepository)
1776
 
        # ask for rev_id
1777
 
        repo.get_parent_map([rev_id])
1778
 
        self.reset_smart_call_log()
1779
 
        # Now asking for rev_id's ghost parent should not make calls
1780
 
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
1781
 
        self.assertLength(0, self.hpss_calls)
1782
 
 
1783
1524
 
1784
1525
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
1785
1526
 
1809
1550
        transport_path = 'empty'
1810
1551
        repo, client = self.setup_fake_client_and_repository(transport_path)
1811
1552
        client.add_success_response('notused')
1812
 
        # actual RemoteRepository.get_revision_graph is gone, but there's an
1813
 
        # equivalent private method for testing
1814
 
        result = repo._get_revision_graph(NULL_REVISION)
 
1553
        result = self.applyDeprecated(one_four, repo.get_revision_graph,
 
1554
            NULL_REVISION)
1815
1555
        self.assertEqual([], client._calls)
1816
1556
        self.assertEqual({}, result)
1817
1557
 
1825
1565
        transport_path = 'sinhala'
1826
1566
        repo, client = self.setup_fake_client_and_repository(transport_path)
1827
1567
        client.add_success_response_with_body(encoded_body, 'ok')
1828
 
        # actual RemoteRepository.get_revision_graph is gone, but there's an
1829
 
        # equivalent private method for testing
1830
 
        result = repo._get_revision_graph(None)
 
1568
        result = self.applyDeprecated(one_four, repo.get_revision_graph)
1831
1569
        self.assertEqual(
1832
1570
            [('call_expecting_body', 'Repository.get_revision_graph',
1833
1571
             ('sinhala/', ''))],
1846
1584
        transport_path = 'sinhala'
1847
1585
        repo, client = self.setup_fake_client_and_repository(transport_path)
1848
1586
        client.add_success_response_with_body(encoded_body, 'ok')
1849
 
        result = repo._get_revision_graph(r2)
 
1587
        result = self.applyDeprecated(one_four, repo.get_revision_graph, r2)
1850
1588
        self.assertEqual(
1851
1589
            [('call_expecting_body', 'Repository.get_revision_graph',
1852
1590
             ('sinhala/', r2))],
1860
1598
        client.add_error_response('nosuchrevision', revid)
1861
1599
        # also check that the right revision is reported in the error
1862
1600
        self.assertRaises(errors.NoSuchRevision,
1863
 
            repo._get_revision_graph, revid)
 
1601
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
1864
1602
        self.assertEqual(
1865
1603
            [('call_expecting_body', 'Repository.get_revision_graph',
1866
1604
             ('sinhala/', revid))],
1872
1610
        repo, client = self.setup_fake_client_and_repository(transport_path)
1873
1611
        client.add_error_response('AnUnexpectedError')
1874
1612
        e = self.assertRaises(errors.UnknownErrorFromSmartServer,
1875
 
            repo._get_revision_graph, revid)
 
1613
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
1876
1614
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
1877
1615
 
1878
1616
 
1996
1734
        self.assertEqual([], client._calls)
1997
1735
 
1998
1736
 
1999
 
class TestRepositoryInsertStream(TestRemoteRepository):
2000
 
 
2001
 
    def test_unlocked_repo(self):
2002
 
        transport_path = 'quack'
2003
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2004
 
        client.add_expected_call(
2005
 
            'Repository.insert_stream', ('quack/', ''),
2006
 
            'success', ('ok',))
2007
 
        client.add_expected_call(
2008
 
            'Repository.insert_stream', ('quack/', ''),
2009
 
            'success', ('ok',))
2010
 
        sink = repo._get_sink()
2011
 
        fmt = repository.RepositoryFormat.get_default_format()
2012
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2013
 
        self.assertEqual([], resume_tokens)
2014
 
        self.assertEqual(set(), missing_keys)
2015
 
        client.finished_test()
2016
 
 
2017
 
    def test_locked_repo_with_no_lock_token(self):
2018
 
        transport_path = 'quack'
2019
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2020
 
        client.add_expected_call(
2021
 
            'Repository.lock_write', ('quack/', ''),
2022
 
            'success', ('ok', ''))
2023
 
        client.add_expected_call(
2024
 
            'Repository.insert_stream', ('quack/', ''),
2025
 
            'success', ('ok',))
2026
 
        client.add_expected_call(
2027
 
            'Repository.insert_stream', ('quack/', ''),
2028
 
            'success', ('ok',))
2029
 
        repo.lock_write()
2030
 
        sink = repo._get_sink()
2031
 
        fmt = repository.RepositoryFormat.get_default_format()
2032
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2033
 
        self.assertEqual([], resume_tokens)
2034
 
        self.assertEqual(set(), missing_keys)
2035
 
        client.finished_test()
2036
 
 
2037
 
    def test_locked_repo_with_lock_token(self):
2038
 
        transport_path = 'quack'
2039
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2040
 
        client.add_expected_call(
2041
 
            'Repository.lock_write', ('quack/', ''),
2042
 
            'success', ('ok', 'a token'))
2043
 
        client.add_expected_call(
2044
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2045
 
            'success', ('ok',))
2046
 
        client.add_expected_call(
2047
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2048
 
            'success', ('ok',))
2049
 
        repo.lock_write()
2050
 
        sink = repo._get_sink()
2051
 
        fmt = repository.RepositoryFormat.get_default_format()
2052
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2053
 
        self.assertEqual([], resume_tokens)
2054
 
        self.assertEqual(set(), missing_keys)
2055
 
        client.finished_test()
2056
 
 
2057
 
 
2058
1737
class TestRepositoryTarball(TestRemoteRepository):
2059
1738
 
2060
1739
    # This is a canned tarball reponse we can validate against
2112
1791
class _StubRealPackRepository(object):
2113
1792
 
2114
1793
    def __init__(self, calls):
2115
 
        self.calls = calls
2116
1794
        self._pack_collection = _StubPackCollection(calls)
2117
1795
 
2118
 
    def is_in_write_group(self):
2119
 
        return False
2120
 
 
2121
 
    def refresh_data(self):
2122
 
        self.calls.append(('pack collection reload_pack_names',))
2123
 
 
2124
1796
 
2125
1797
class _StubPackCollection(object):
2126
1798
 
2130
1802
    def autopack(self):
2131
1803
        self.calls.append(('pack collection autopack',))
2132
1804
 
 
1805
    def reload_pack_names(self):
 
1806
        self.calls.append(('pack collection reload_pack_names',))
 
1807
 
2133
1808
 
2134
1809
class TestRemotePackRepositoryAutoPack(TestRemoteRepository):
2135
1810
    """Tests for RemoteRepository.autopack implementation."""
2389
2064
        # revision, then open it over hpss - we should be able to see that
2390
2065
        # revision.
2391
2066
        base_transport = self.get_transport()
2392
 
        base_builder = self.make_branch_builder('base', format='1.9')
 
2067
        base_builder = self.make_branch_builder('base', format='1.6')
2393
2068
        base_builder.start_series()
2394
2069
        base_revid = base_builder.build_snapshot('rev-id', None,
2395
2070
            [('add', ('', None, 'directory', None))],
2396
2071
            'message')
2397
2072
        base_builder.finish_series()
2398
 
        stacked_branch = self.make_branch('stacked', format='1.9')
 
2073
        stacked_branch = self.make_branch('stacked', format='1.6')
2399
2074
        stacked_branch.set_stacked_on_url('../base')
2400
2075
        # start a server looking at this
2401
2076
        smart_server = server.SmartTCPServer_for_testing()
2422
2097
            remote_repo.unlock()
2423
2098
 
2424
2099
    def prepare_stacked_remote_branch(self):
2425
 
        """Get stacked_upon and stacked branches with content in each."""
2426
 
        self.setup_smart_server_with_call_log()
2427
 
        tree1 = self.make_branch_and_tree('tree1', format='1.9')
 
2100
        smart_server = server.SmartTCPServer_for_testing()
 
2101
        smart_server.setUp()
 
2102
        self.addCleanup(smart_server.tearDown)
 
2103
        tree1 = self.make_branch_and_tree('tree1')
2428
2104
        tree1.commit('rev1', rev_id='rev1')
2429
 
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2430
 
            ).open_workingtree()
2431
 
        tree2.commit('local changes make me feel good.')
2432
 
        branch2 = Branch.open(self.get_url('tree2'))
 
2105
        tree2 = self.make_branch_and_tree('tree2', format='1.6')
 
2106
        tree2.branch.set_stacked_on_url(tree1.branch.base)
 
2107
        branch2 = Branch.open(smart_server.get_url() + '/tree2')
2433
2108
        branch2.lock_read()
2434
2109
        self.addCleanup(branch2.unlock)
2435
 
        return tree1.branch, branch2
 
2110
        return branch2
2436
2111
 
2437
2112
    def test_stacked_get_parent_map(self):
2438
2113
        # the public implementation of get_parent_map obeys stacking
2439
 
        _, branch = self.prepare_stacked_remote_branch()
 
2114
        branch = self.prepare_stacked_remote_branch()
2440
2115
        repo = branch.repository
2441
2116
        self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
2442
2117
 
2443
2118
    def test_unstacked_get_parent_map(self):
2444
2119
        # _unstacked_provider.get_parent_map ignores stacking
2445
 
        _, branch = self.prepare_stacked_remote_branch()
 
2120
        branch = self.prepare_stacked_remote_branch()
2446
2121
        provider = branch.repository._unstacked_provider
2447
2122
        self.assertEqual([], provider.get_parent_map(['rev1']).keys())
2448
2123
 
2449
 
    def fetch_stream_to_rev_order(self, stream):
2450
 
        result = []
2451
 
        for kind, substream in stream:
2452
 
            if not kind == 'revisions':
2453
 
                list(substream)
2454
 
            else:
2455
 
                for content in substream:
2456
 
                    result.append(content.key[-1])
2457
 
        return result
2458
 
 
2459
 
    def get_ordered_revs(self, format, order):
2460
 
        """Get a list of the revisions in a stream to format format.
2461
 
 
2462
 
        :param format: The format of the target.
2463
 
        :param order: the order that target should have requested.
2464
 
        :result: The revision ids in the stream, in the order seen,
2465
 
            the topological order of revisions in the source.
2466
 
        """
2467
 
        unordered_format = bzrdir.format_registry.get(format)()
2468
 
        target_repository_format = unordered_format.repository_format
2469
 
        # Cross check
2470
 
        self.assertEqual(order, target_repository_format._fetch_order)
2471
 
        trunk, stacked = self.prepare_stacked_remote_branch()
2472
 
        source = stacked.repository._get_source(target_repository_format)
2473
 
        tip = stacked.last_revision()
2474
 
        revs = stacked.repository.get_ancestry(tip)
2475
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
2476
 
        self.reset_smart_call_log()
2477
 
        stream = source.get_stream(search)
2478
 
        if None in revs:
2479
 
            revs.remove(None)
2480
 
        # We trust that if a revision is in the stream the rest of the new
2481
 
        # content for it is too, as per our main fetch tests; here we are
2482
 
        # checking that the revisions are actually included at all, and their
2483
 
        # order.
2484
 
        return self.fetch_stream_to_rev_order(stream), revs
2485
 
 
2486
 
    def test_stacked_get_stream_unordered(self):
2487
 
        # Repository._get_source.get_stream() from a stacked repository with
2488
 
        # unordered yields the full data from both stacked and stacked upon
2489
 
        # sources.
2490
 
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered')
2491
 
        self.assertEqual(set(expected_revs), set(rev_ord))
2492
 
        # Getting unordered results should have made a streaming data request
2493
 
        # from the server, then one from the backing branch.
2494
 
        self.assertLength(2, self.hpss_calls)
2495
 
 
2496
 
    def test_stacked_get_stream_topological(self):
2497
 
        # Repository._get_source.get_stream() from a stacked repository with
2498
 
        # topological sorting yields the full data from both stacked and
2499
 
        # stacked upon sources in topological order.
2500
 
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
2501
 
        self.assertEqual(expected_revs, rev_ord)
2502
 
        # Getting topological sort requires VFS calls still
2503
 
        self.assertLength(12, self.hpss_calls)
2504
 
 
2505
 
    def test_stacked_get_stream_groupcompress(self):
2506
 
        # Repository._get_source.get_stream() from a stacked repository with
2507
 
        # groupcompress sorting yields the full data from both stacked and
2508
 
        # stacked upon sources in groupcompress order.
2509
 
        raise tests.TestSkipped('No groupcompress ordered format available')
2510
 
        rev_ord, expected_revs = self.get_ordered_revs('dev5', 'groupcompress')
2511
 
        self.assertEqual(expected_revs, reversed(rev_ord))
2512
 
        # Getting unordered results should have made a streaming data request
2513
 
        # from the backing branch, and one from the stacked on branch.
2514
 
        self.assertLength(2, self.hpss_calls)
2515
 
 
2516
2124
 
2517
2125
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
2518
2126