~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Gary van der Merwe
  • Date: 2010-08-02 19:56:52 UTC
  • mfrom: (5050.3.18 2.2)
  • mto: (5050.3.19 2.2)
  • mto: This revision was merged to the branch mainline in revision 5371.
  • Revision ID: garyvdm@gmail.com-20100802195652-o1ppjemhwrr98i61
Merge lp:bzr/2.2.

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-2010 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
27
27
from cStringIO import StringIO
28
28
 
29
29
from bzrlib import (
 
30
    branch,
30
31
    bzrdir,
31
32
    config,
32
33
    errors,
33
34
    graph,
 
35
    inventory,
 
36
    inventory_delta,
34
37
    pack,
35
38
    remote,
36
39
    repository,
37
 
    smart,
38
40
    tests,
 
41
    transport,
39
42
    treebuilder,
40
43
    urlutils,
 
44
    versionedfile,
41
45
    )
42
46
from bzrlib.branch import Branch
43
47
from bzrlib.bzrdir import BzrDir, BzrDirFormat
51
55
    )
52
56
from bzrlib.repofmt import groupcompress_repo, pack_repo
53
57
from bzrlib.revision import NULL_REVISION
54
 
from bzrlib.smart import server, medium
 
58
from bzrlib.smart import medium
55
59
from bzrlib.smart.client import _SmartClient
56
60
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
57
61
from bzrlib.tests import (
58
62
    condition_isinstance,
59
63
    split_suite_by_condition,
60
64
    multiply_tests,
61
 
    KnownFailure,
 
65
    test_server,
62
66
    )
63
 
from bzrlib.transport import get_transport, http
64
67
from bzrlib.transport.memory import MemoryTransport
65
68
from bzrlib.transport.remote import (
66
69
    RemoteTransport,
73
76
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
74
77
    smart_server_version_scenarios = [
75
78
        ('HPSS-v2',
76
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
 
79
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
77
80
        ('HPSS-v3',
78
 
            {'transport_server': server.SmartTCPServer_for_testing})]
 
81
         {'transport_server': test_server.SmartTCPServer_for_testing})]
79
82
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
80
83
 
81
84
 
132
135
        b = BzrDir.open_from_transport(self.transport).open_branch()
133
136
        self.assertStartsWith(str(b), 'RemoteBranch(')
134
137
 
 
138
    def test_remote_bzrdir_repr(self):
 
139
        b = BzrDir.open_from_transport(self.transport)
 
140
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
 
141
 
135
142
    def test_remote_branch_format_supports_stacking(self):
136
143
        t = self.transport
137
144
        self.make_branch('unstackable', format='pack-0.92')
277
284
        self.expecting_body = True
278
285
        return result[1], FakeProtocol(result[2], self)
279
286
 
 
287
    def call_with_body_bytes(self, method, args, body):
 
288
        self._check_call(method, args)
 
289
        self._calls.append(('call_with_body_bytes', method, args, body))
 
290
        result = self._get_next_response()
 
291
        return result[1], FakeProtocol(result[2], self)
 
292
 
280
293
    def call_with_body_bytes_expecting_body(self, method, args, body):
281
294
        self._check_call(method, args)
282
295
        self._calls.append(('call_with_body_bytes_expecting_body', method,
332
345
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
333
346
        return reference_bzrdir_format.repository_format
334
347
 
335
 
    def disable_verb(self, verb):
336
 
        """Disable a verb for one test."""
337
 
        request_handlers = smart.request.request_handlers
338
 
        orig_method = request_handlers.get(verb)
339
 
        request_handlers.remove(verb)
340
 
        def restoreVerb():
341
 
            request_handlers.register(verb, orig_method)
342
 
        self.addCleanup(restoreVerb)
343
 
 
344
348
    def assertFinished(self, fake_client):
345
349
        """Assert that all of a FakeClient's expected calls have occurred."""
346
350
        fake_client.finished_test()
355
359
        a given client_base and transport_base.
356
360
        """
357
361
        client_medium = medium.SmartClientMedium(client_base)
358
 
        transport = get_transport(transport_base)
359
 
        result = client_medium.remote_path_from_transport(transport)
 
362
        t = transport.get_transport(transport_base)
 
363
        result = client_medium.remote_path_from_transport(t)
360
364
        self.assertEqual(expected, result)
361
365
 
362
366
    def test_remote_path_from_transport(self):
373
377
        a given transport_base and relpath of that transport.  (Note that
374
378
        HttpTransportBase is a subclass of SmartClientMedium)
375
379
        """
376
 
        base_transport = get_transport(transport_base)
 
380
        base_transport = transport.get_transport(transport_base)
377
381
        client_medium = base_transport.get_smart_medium()
378
382
        cloned_transport = base_transport.clone(relpath)
379
383
        result = client_medium.remote_path_from_transport(cloned_transport)
414
418
        # Calling _remember_remote_is_before again with a lower value works.
415
419
        client_medium._remember_remote_is_before((1, 5))
416
420
        self.assertTrue(client_medium._is_remote_before((1, 5)))
417
 
        # You cannot call _remember_remote_is_before with a larger value.
418
 
        self.assertRaises(
419
 
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
 
421
        # If you call _remember_remote_is_before with a higher value it logs a
 
422
        # warning, and continues to remember the lower value.
 
423
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
 
424
        client_medium._remember_remote_is_before((1, 9))
 
425
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
 
426
        self.assertTrue(client_medium._is_remote_before((1, 5)))
420
427
 
421
428
 
422
429
class TestBzrDirCloningMetaDir(TestRemote):
441
448
            'BzrDir.cloning_metadir', ('quack/', 'False'),
442
449
            'error', ('BranchReference',)),
443
450
        client.add_expected_call(
444
 
            'BzrDir.open_branchV2', ('quack/',),
 
451
            'BzrDir.open_branchV3', ('quack/',),
445
452
            'success', ('ref', self.get_url('referenced'))),
446
453
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
447
454
            _client=client)
474
481
        self.assertFinished(client)
475
482
 
476
483
 
 
484
class TestBzrDirOpen(TestRemote):
 
485
 
 
486
    def make_fake_client_and_transport(self, path='quack'):
 
487
        transport = MemoryTransport()
 
488
        transport.mkdir(path)
 
489
        transport = transport.clone(path)
 
490
        client = FakeClient(transport.base)
 
491
        return client, transport
 
492
 
 
493
    def test_absent(self):
 
494
        client, transport = self.make_fake_client_and_transport()
 
495
        client.add_expected_call(
 
496
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
 
497
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
 
498
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
499
        self.assertFinished(client)
 
500
 
 
501
    def test_present_without_workingtree(self):
 
502
        client, transport = self.make_fake_client_and_transport()
 
503
        client.add_expected_call(
 
504
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
 
505
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
506
            _client=client, _force_probe=True)
 
507
        self.assertIsInstance(bd, RemoteBzrDir)
 
508
        self.assertFalse(bd.has_workingtree())
 
509
        self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
 
510
        self.assertFinished(client)
 
511
 
 
512
    def test_present_with_workingtree(self):
 
513
        client, transport = self.make_fake_client_and_transport()
 
514
        client.add_expected_call(
 
515
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
 
516
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
517
            _client=client, _force_probe=True)
 
518
        self.assertIsInstance(bd, RemoteBzrDir)
 
519
        self.assertTrue(bd.has_workingtree())
 
520
        self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
 
521
        self.assertFinished(client)
 
522
 
 
523
    def test_backwards_compat(self):
 
524
        client, transport = self.make_fake_client_and_transport()
 
525
        client.add_expected_call(
 
526
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
527
        client.add_expected_call(
 
528
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
529
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
530
            _client=client, _force_probe=True)
 
531
        self.assertIsInstance(bd, RemoteBzrDir)
 
532
        self.assertFinished(client)
 
533
 
 
534
    def test_backwards_compat_hpss_v2(self):
 
535
        client, transport = self.make_fake_client_and_transport()
 
536
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
537
        # server: upon first RPC call detect the protocol version, and because
 
538
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
539
        # continuing with the RPC.
 
540
        orig_check_call = client._check_call
 
541
        def check_call(method, args):
 
542
            client._medium._protocol_version = 2
 
543
            client._medium._remember_remote_is_before((1, 6))
 
544
            client._check_call = orig_check_call
 
545
            client._check_call(method, args)
 
546
        client._check_call = check_call
 
547
        client.add_expected_call(
 
548
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
549
        client.add_expected_call(
 
550
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
551
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
552
            _client=client, _force_probe=True)
 
553
        self.assertIsInstance(bd, RemoteBzrDir)
 
554
        self.assertFinished(client)
 
555
 
 
556
 
477
557
class TestBzrDirOpenBranch(TestRemote):
478
558
 
479
559
    def test_backwards_compat(self):
481
561
        self.make_branch('.')
482
562
        a_dir = BzrDir.open(self.get_url('.'))
483
563
        self.reset_smart_call_log()
484
 
        verb = 'BzrDir.open_branchV2'
 
564
        verb = 'BzrDir.open_branchV3'
485
565
        self.disable_verb(verb)
486
566
        format = a_dir.open_branch()
487
567
        call_count = len([call for call in self.hpss_calls if
497
577
        transport = transport.clone('quack')
498
578
        client = FakeClient(transport.base)
499
579
        client.add_expected_call(
500
 
            'BzrDir.open_branchV2', ('quack/',),
 
580
            'BzrDir.open_branchV3', ('quack/',),
501
581
            'success', ('branch', branch_network_name))
502
582
        client.add_expected_call(
503
583
            'BzrDir.find_repositoryV3', ('quack/',),
522
602
            _client=client)
523
603
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
524
604
        self.assertEqual(
525
 
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
 
605
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
526
606
            client._calls)
527
607
 
528
608
    def test__get_tree_branch(self):
529
609
        # _get_tree_branch is a form of open_branch, but it should only ask for
530
610
        # branch opening, not any other network requests.
531
611
        calls = []
532
 
        def open_branch():
 
612
        def open_branch(name=None):
533
613
            calls.append("Called")
534
614
            return "a-branch"
535
615
        transport = MemoryTransport()
552
632
        network_name = reference_format.network_name()
553
633
        branch_network_name = self.get_branch_format().network_name()
554
634
        client.add_expected_call(
555
 
            'BzrDir.open_branchV2', ('~hello/',),
 
635
            'BzrDir.open_branchV3', ('~hello/',),
556
636
            'success', ('branch', branch_network_name))
557
637
        client.add_expected_call(
558
638
            'BzrDir.find_repositoryV3', ('~hello/',),
667
747
        network_name = reference_format.network_name()
668
748
        client.add_expected_call(
669
749
            'BzrDir.create_repository', ('quack/',
670
 
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
671
 
            'success', ('ok', 'no', 'no', 'no', network_name))
 
750
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
751
                'False'),
 
752
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
672
753
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
673
754
            _client=client)
674
755
        repo = a_bzrdir.create_repository()
676
757
        self.assertIsInstance(repo, remote.RemoteRepository)
677
758
        # its format should have the settings from the response
678
759
        format = repo._format
679
 
        self.assertFalse(format.rich_root_data)
680
 
        self.assertFalse(format.supports_tree_reference)
681
 
        self.assertFalse(format.supports_external_lookups)
 
760
        self.assertTrue(format.rich_root_data)
 
761
        self.assertTrue(format.supports_tree_reference)
 
762
        self.assertTrue(format.supports_external_lookups)
682
763
        self.assertEqual(network_name, format.network_name())
683
764
 
684
765
 
688
769
        # fallback all the way to the first version.
689
770
        reference_format = self.get_repo_format()
690
771
        network_name = reference_format.network_name()
691
 
        client = FakeClient('bzr://example.com/')
 
772
        server_url = 'bzr://example.com/'
 
773
        self.permit_url(server_url)
 
774
        client = FakeClient(server_url)
692
775
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
693
776
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
694
777
        client.add_success_response('ok', '', 'no', 'no')
700
783
            reference_format.get_format_string(), 'ok')
701
784
        # PackRepository wants to do a stat
702
785
        client.add_success_response('stat', '0', '65535')
703
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
786
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
704
787
            _client=client)
705
788
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
706
789
            _client=client)
720
803
        # fallback to find_repositoryV2
721
804
        reference_format = self.get_repo_format()
722
805
        network_name = reference_format.network_name()
723
 
        client = FakeClient('bzr://example.com/')
 
806
        server_url = 'bzr://example.com/'
 
807
        self.permit_url(server_url)
 
808
        client = FakeClient(server_url)
724
809
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
725
810
        client.add_success_response('ok', '', 'no', 'no', 'no')
726
811
        # A real repository instance will be created to determine the network
731
816
            reference_format.get_format_string(), 'ok')
732
817
        # PackRepository wants to do a stat
733
818
        client.add_success_response('stat', '0', '65535')
734
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
819
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
735
820
            _client=client)
736
821
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
737
822
            _client=client)
856
941
 
857
942
class RemoteBranchTestCase(RemoteBzrDirTestCase):
858
943
 
 
944
    def lock_remote_branch(self, branch):
 
945
        """Trick a RemoteBranch into thinking it is locked."""
 
946
        branch._lock_mode = 'w'
 
947
        branch._lock_count = 2
 
948
        branch._lock_token = 'branch token'
 
949
        branch._repo_lock_token = 'repo token'
 
950
        branch.repository._lock_mode = 'w'
 
951
        branch.repository._lock_count = 2
 
952
        branch.repository._lock_token = 'repo token'
 
953
 
859
954
    def make_remote_branch(self, transport, client):
860
955
        """Make a RemoteBranch using 'client' as its _SmartClient.
861
956
 
1000
1095
        self.assertEqual({}, result)
1001
1096
 
1002
1097
 
 
1098
class TestBranchSetTagsBytes(RemoteBranchTestCase):
 
1099
 
 
1100
    def test_trivial(self):
 
1101
        transport = MemoryTransport()
 
1102
        client = FakeClient(transport.base)
 
1103
        client.add_expected_call(
 
1104
            'Branch.get_stacked_on_url', ('quack/',),
 
1105
            'error', ('NotStacked',))
 
1106
        client.add_expected_call(
 
1107
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1108
            'success', ('',))
 
1109
        transport.mkdir('quack')
 
1110
        transport = transport.clone('quack')
 
1111
        branch = self.make_remote_branch(transport, client)
 
1112
        self.lock_remote_branch(branch)
 
1113
        branch._set_tags_bytes('tags bytes')
 
1114
        self.assertFinished(client)
 
1115
        self.assertEqual('tags bytes', client._calls[-1][-1])
 
1116
 
 
1117
    def test_backwards_compatible(self):
 
1118
        transport = MemoryTransport()
 
1119
        client = FakeClient(transport.base)
 
1120
        client.add_expected_call(
 
1121
            'Branch.get_stacked_on_url', ('quack/',),
 
1122
            'error', ('NotStacked',))
 
1123
        client.add_expected_call(
 
1124
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1125
            'unknown', ('Branch.set_tags_bytes',))
 
1126
        transport.mkdir('quack')
 
1127
        transport = transport.clone('quack')
 
1128
        branch = self.make_remote_branch(transport, client)
 
1129
        self.lock_remote_branch(branch)
 
1130
        class StubRealBranch(object):
 
1131
            def __init__(self):
 
1132
                self.calls = []
 
1133
            def _set_tags_bytes(self, bytes):
 
1134
                self.calls.append(('set_tags_bytes', bytes))
 
1135
        real_branch = StubRealBranch()
 
1136
        branch._real_branch = real_branch
 
1137
        branch._set_tags_bytes('tags bytes')
 
1138
        # Call a second time, to exercise the 'remote version already inferred'
 
1139
        # code path.
 
1140
        branch._set_tags_bytes('tags bytes')
 
1141
        self.assertFinished(client)
 
1142
        self.assertEqual(
 
1143
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
 
1144
 
 
1145
 
1003
1146
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1004
1147
 
1005
1148
    def test_empty_branch(self):
1077
1220
        client = FakeClient(self.get_url())
1078
1221
        branch_network_name = self.get_branch_format().network_name()
1079
1222
        client.add_expected_call(
1080
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1223
            'BzrDir.open_branchV3', ('stacked/',),
1081
1224
            'success', ('branch', branch_network_name))
1082
1225
        client.add_expected_call(
1083
1226
            'BzrDir.find_repositoryV3', ('stacked/',),
1105
1248
            len(branch.repository._real_repository._fallback_repositories))
1106
1249
 
1107
1250
    def test_get_stacked_on_real_branch(self):
1108
 
        base_branch = self.make_branch('base', format='1.6')
1109
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1251
        base_branch = self.make_branch('base')
 
1252
        stacked_branch = self.make_branch('stacked')
1110
1253
        stacked_branch.set_stacked_on_url('../base')
1111
1254
        reference_format = self.get_repo_format()
1112
1255
        network_name = reference_format.network_name()
1113
1256
        client = FakeClient(self.get_url())
1114
1257
        branch_network_name = self.get_branch_format().network_name()
1115
1258
        client.add_expected_call(
1116
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1259
            'BzrDir.open_branchV3', ('stacked/',),
1117
1260
            'success', ('branch', branch_network_name))
1118
1261
        client.add_expected_call(
1119
1262
            'BzrDir.find_repositoryV3', ('stacked/',),
1120
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1263
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1121
1264
        # called twice, once from constructor and then again by us
1122
1265
        client.add_expected_call(
1123
1266
            'Branch.get_stacked_on_url', ('stacked/',),
1347
1490
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1348
1491
        branch.unlock()
1349
1492
 
1350
 
    def lock_remote_branch(self, branch):
1351
 
        """Trick a RemoteBranch into thinking it is locked."""
1352
 
        branch._lock_mode = 'w'
1353
 
        branch._lock_count = 2
1354
 
        branch._lock_token = 'branch token'
1355
 
        branch._repo_lock_token = 'repo token'
1356
 
        branch.repository._lock_mode = 'w'
1357
 
        branch.repository._lock_count = 2
1358
 
        branch.repository._lock_token = 'repo token'
1359
 
 
1360
1493
    def test_backwards_compatibility(self):
1361
1494
        """If the server does not support the Branch.set_last_revision_info
1362
1495
        verb (which is new in 1.4), then the client falls back to VFS methods.
1485
1618
    def test_get_multi_line_branch_conf(self):
1486
1619
        # Make sure that multiple-line branch.conf files are supported
1487
1620
        #
1488
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1621
        # https://bugs.launchpad.net/bzr/+bug/354075
1489
1622
        client = FakeClient()
1490
1623
        client.add_expected_call(
1491
1624
            'Branch.get_stacked_on_url', ('memory:///',),
1519
1652
        branch.unlock()
1520
1653
        self.assertFinished(client)
1521
1654
 
 
1655
    def test_set_option_with_dict(self):
 
1656
        client = FakeClient()
 
1657
        client.add_expected_call(
 
1658
            'Branch.get_stacked_on_url', ('memory:///',),
 
1659
            'error', ('NotStacked',),)
 
1660
        client.add_expected_call(
 
1661
            'Branch.lock_write', ('memory:///', '', ''),
 
1662
            'success', ('ok', 'branch token', 'repo token'))
 
1663
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1664
        client.add_expected_call(
 
1665
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1666
            'repo token', encoded_dict_value, 'foo', ''),
 
1667
            'success', ())
 
1668
        client.add_expected_call(
 
1669
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1670
            'success', ('ok',))
 
1671
        transport = MemoryTransport()
 
1672
        branch = self.make_remote_branch(transport, client)
 
1673
        branch.lock_write()
 
1674
        config = branch._get_config()
 
1675
        config.set_option(
 
1676
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1677
            'foo')
 
1678
        branch.unlock()
 
1679
        self.assertFinished(client)
 
1680
 
1522
1681
    def test_backwards_compat_set_option(self):
1523
1682
        self.setup_smart_server_with_call_log()
1524
1683
        branch = self.make_branch('.')
1531
1690
        self.assertLength(10, self.hpss_calls)
1532
1691
        self.assertEqual('value', branch._get_config().get_option('name'))
1533
1692
 
 
1693
    def test_backwards_compat_set_option_with_dict(self):
 
1694
        self.setup_smart_server_with_call_log()
 
1695
        branch = self.make_branch('.')
 
1696
        verb = 'Branch.set_config_option_dict'
 
1697
        self.disable_verb(verb)
 
1698
        branch.lock_write()
 
1699
        self.addCleanup(branch.unlock)
 
1700
        self.reset_smart_call_log()
 
1701
        config = branch._get_config()
 
1702
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
1703
        config.set_option(value_dict, 'name')
 
1704
        self.assertLength(10, self.hpss_calls)
 
1705
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
1706
 
1534
1707
 
1535
1708
class TestBranchLockWrite(RemoteBranchTestCase):
1536
1709
 
1678
1851
        return repo, client
1679
1852
 
1680
1853
 
 
1854
def remoted_description(format):
 
1855
    return 'Remote: ' + format.get_format_description()
 
1856
 
 
1857
 
 
1858
class TestBranchFormat(tests.TestCase):
 
1859
 
 
1860
    def test_get_format_description(self):
 
1861
        remote_format = RemoteBranchFormat()
 
1862
        real_format = branch.BranchFormat.get_default_format()
 
1863
        remote_format._network_name = real_format.network_name()
 
1864
        self.assertEqual(remoted_description(real_format),
 
1865
            remote_format.get_format_description())
 
1866
 
 
1867
 
1681
1868
class TestRepositoryFormat(TestRemoteRepository):
1682
1869
 
1683
1870
    def test_fast_delta(self):
1690
1877
        false_format._network_name = false_name
1691
1878
        self.assertEqual(False, false_format.fast_deltas)
1692
1879
 
 
1880
    def test_get_format_description(self):
 
1881
        remote_repo_format = RemoteRepositoryFormat()
 
1882
        real_format = repository.RepositoryFormat.get_default_format()
 
1883
        remote_repo_format._network_name = real_format.network_name()
 
1884
        self.assertEqual(remoted_description(real_format),
 
1885
            remote_repo_format.get_format_description())
 
1886
 
1693
1887
 
1694
1888
class TestRepositoryGatherStats(TestRemoteRepository):
1695
1889
 
1880
2074
        self.assertLength(1, self.hpss_calls)
1881
2075
 
1882
2076
    def disableExtraResults(self):
1883
 
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
1884
 
        SmartServerRepositoryGetParentMap.no_extra_results = True
1885
 
        def reset_values():
1886
 
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
1887
 
        self.addCleanup(reset_values)
 
2077
        self.overrideAttr(SmartServerRepositoryGetParentMap,
 
2078
                          'no_extra_results', True)
1888
2079
 
1889
2080
    def test_null_cached_missing_and_stop_key(self):
1890
2081
        self.setup_smart_server_with_call_log()
1949
2140
 
1950
2141
    def test_allows_new_revisions(self):
1951
2142
        """get_parent_map's results can be updated by commit."""
1952
 
        smart_server = server.SmartTCPServer_for_testing()
1953
 
        smart_server.setUp()
1954
 
        self.addCleanup(smart_server.tearDown)
 
2143
        smart_server = test_server.SmartTCPServer_for_testing()
 
2144
        self.start_server(smart_server)
1955
2145
        self.make_branch('branch')
1956
2146
        branch = Branch.open(smart_server.get_url() + '/branch')
1957
2147
        tree = branch.create_checkout('tree', lightweight=True)
2066
2256
        """
2067
2257
        # Make a repo with a fallback repo, both using a FakeClient.
2068
2258
        format = remote.response_tuple_to_repo_format(
2069
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2259
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2070
2260
        repo, client = self.setup_fake_client_and_repository('quack')
2071
2261
        repo._format = format
2072
2262
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2073
2263
            'fallback')
2074
2264
        fallback_repo._client = client
 
2265
        fallback_repo._format = format
2075
2266
        repo.add_fallback_repository(fallback_repo)
2076
2267
        # First the client should ask the primary repo
2077
2268
        client.add_expected_call(
2098
2289
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2099
2290
        self.assertFinished(client)
2100
2291
 
 
2292
    def test_branch_fallback_locking(self):
 
2293
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
 
2294
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
 
2295
        will be invoked, which will fail if the repo is unlocked.
 
2296
        """
 
2297
        self.setup_smart_server_with_call_log()
 
2298
        tree = self.make_branch_and_memory_tree('.')
 
2299
        tree.lock_write()
 
2300
        tree.add('')
 
2301
        rev1 = tree.commit('First')
 
2302
        rev2 = tree.commit('Second')
 
2303
        tree.unlock()
 
2304
        branch = tree.branch
 
2305
        self.assertFalse(branch.is_locked())
 
2306
        self.reset_smart_call_log()
 
2307
        verb = 'Repository.get_rev_id_for_revno'
 
2308
        self.disable_verb(verb)
 
2309
        self.assertEqual(rev1, branch.get_rev_id(1))
 
2310
        self.assertLength(1, [call for call in self.hpss_calls if
 
2311
                              call.call.method == verb])
 
2312
 
2101
2313
 
2102
2314
class TestRepositoryIsShared(TestRemoteRepository):
2103
2315
 
2130
2342
        transport_path = 'quack'
2131
2343
        repo, client = self.setup_fake_client_and_repository(transport_path)
2132
2344
        client.add_success_response('ok', 'a token')
2133
 
        result = repo.lock_write()
 
2345
        token = repo.lock_write().repository_token
2134
2346
        self.assertEqual(
2135
2347
            [('call', 'Repository.lock_write', ('quack/', ''))],
2136
2348
            client._calls)
2137
 
        self.assertEqual('a token', result)
 
2349
        self.assertEqual('a token', token)
2138
2350
 
2139
2351
    def test_lock_write_already_locked(self):
2140
2352
        transport_path = 'quack'
2219
2431
        self.assertEqual([], client._calls)
2220
2432
 
2221
2433
 
2222
 
class TestRepositoryInsertStream(TestRemoteRepository):
2223
 
 
2224
 
    def test_unlocked_repo(self):
2225
 
        transport_path = 'quack'
2226
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2227
 
        client.add_expected_call(
2228
 
            'Repository.insert_stream', ('quack/', ''),
2229
 
            'success', ('ok',))
2230
 
        client.add_expected_call(
2231
 
            'Repository.insert_stream', ('quack/', ''),
2232
 
            'success', ('ok',))
2233
 
        sink = repo._get_sink()
2234
 
        fmt = repository.RepositoryFormat.get_default_format()
2235
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2236
 
        self.assertEqual([], resume_tokens)
2237
 
        self.assertEqual(set(), missing_keys)
2238
 
        self.assertFinished(client)
2239
 
 
2240
 
    def test_locked_repo_with_no_lock_token(self):
2241
 
        transport_path = 'quack'
2242
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2243
 
        client.add_expected_call(
2244
 
            'Repository.lock_write', ('quack/', ''),
2245
 
            'success', ('ok', ''))
2246
 
        client.add_expected_call(
2247
 
            'Repository.insert_stream', ('quack/', ''),
2248
 
            'success', ('ok',))
2249
 
        client.add_expected_call(
2250
 
            'Repository.insert_stream', ('quack/', ''),
2251
 
            'success', ('ok',))
2252
 
        repo.lock_write()
2253
 
        sink = repo._get_sink()
2254
 
        fmt = repository.RepositoryFormat.get_default_format()
2255
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2256
 
        self.assertEqual([], resume_tokens)
2257
 
        self.assertEqual(set(), missing_keys)
2258
 
        self.assertFinished(client)
2259
 
 
2260
 
    def test_locked_repo_with_lock_token(self):
2261
 
        transport_path = 'quack'
2262
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2263
 
        client.add_expected_call(
2264
 
            'Repository.lock_write', ('quack/', ''),
2265
 
            'success', ('ok', 'a token'))
2266
 
        client.add_expected_call(
2267
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2268
 
            'success', ('ok',))
2269
 
        client.add_expected_call(
2270
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2271
 
            'success', ('ok',))
2272
 
        repo.lock_write()
2273
 
        sink = repo._get_sink()
2274
 
        fmt = repository.RepositoryFormat.get_default_format()
2275
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2276
 
        self.assertEqual([], resume_tokens)
2277
 
        self.assertEqual(set(), missing_keys)
2278
 
        self.assertFinished(client)
 
2434
class TestRepositoryInsertStreamBase(TestRemoteRepository):
 
2435
    """Base class for Repository.insert_stream and .insert_stream_1.19
 
2436
    tests.
 
2437
    """
 
2438
    
 
2439
    def checkInsertEmptyStream(self, repo, client):
 
2440
        """Insert an empty stream, checking the result.
 
2441
 
 
2442
        This checks that there are no resume_tokens or missing_keys, and that
 
2443
        the client is finished.
 
2444
        """
 
2445
        sink = repo._get_sink()
 
2446
        fmt = repository.RepositoryFormat.get_default_format()
 
2447
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2448
        self.assertEqual([], resume_tokens)
 
2449
        self.assertEqual(set(), missing_keys)
 
2450
        self.assertFinished(client)
 
2451
 
 
2452
 
 
2453
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
 
2454
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
 
2455
    not available.
 
2456
 
 
2457
    This test case is very similar to TestRepositoryInsertStream_1_19.
 
2458
    """
 
2459
 
 
2460
    def setUp(self):
 
2461
        TestRemoteRepository.setUp(self)
 
2462
        self.disable_verb('Repository.insert_stream_1.19')
 
2463
 
 
2464
    def test_unlocked_repo(self):
 
2465
        transport_path = 'quack'
 
2466
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2467
        client.add_expected_call(
 
2468
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2469
            'unknown', ('Repository.insert_stream_1.19',))
 
2470
        client.add_expected_call(
 
2471
            'Repository.insert_stream', ('quack/', ''),
 
2472
            'success', ('ok',))
 
2473
        client.add_expected_call(
 
2474
            'Repository.insert_stream', ('quack/', ''),
 
2475
            'success', ('ok',))
 
2476
        self.checkInsertEmptyStream(repo, client)
 
2477
 
 
2478
    def test_locked_repo_with_no_lock_token(self):
 
2479
        transport_path = 'quack'
 
2480
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2481
        client.add_expected_call(
 
2482
            'Repository.lock_write', ('quack/', ''),
 
2483
            'success', ('ok', ''))
 
2484
        client.add_expected_call(
 
2485
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2486
            'unknown', ('Repository.insert_stream_1.19',))
 
2487
        client.add_expected_call(
 
2488
            'Repository.insert_stream', ('quack/', ''),
 
2489
            'success', ('ok',))
 
2490
        client.add_expected_call(
 
2491
            'Repository.insert_stream', ('quack/', ''),
 
2492
            'success', ('ok',))
 
2493
        repo.lock_write()
 
2494
        self.checkInsertEmptyStream(repo, client)
 
2495
 
 
2496
    def test_locked_repo_with_lock_token(self):
 
2497
        transport_path = 'quack'
 
2498
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2499
        client.add_expected_call(
 
2500
            'Repository.lock_write', ('quack/', ''),
 
2501
            'success', ('ok', 'a token'))
 
2502
        client.add_expected_call(
 
2503
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2504
            'unknown', ('Repository.insert_stream_1.19',))
 
2505
        client.add_expected_call(
 
2506
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2507
            'success', ('ok',))
 
2508
        client.add_expected_call(
 
2509
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2510
            'success', ('ok',))
 
2511
        repo.lock_write()
 
2512
        self.checkInsertEmptyStream(repo, client)
 
2513
 
 
2514
    def test_stream_with_inventory_deltas(self):
 
2515
        """'inventory-deltas' substreams cannot be sent to the
 
2516
        Repository.insert_stream verb, because not all servers that implement
 
2517
        that verb will accept them.  So when one is encountered the RemoteSink
 
2518
        immediately stops using that verb and falls back to VFS insert_stream.
 
2519
        """
 
2520
        transport_path = 'quack'
 
2521
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2522
        client.add_expected_call(
 
2523
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2524
            'unknown', ('Repository.insert_stream_1.19',))
 
2525
        client.add_expected_call(
 
2526
            'Repository.insert_stream', ('quack/', ''),
 
2527
            'success', ('ok',))
 
2528
        client.add_expected_call(
 
2529
            'Repository.insert_stream', ('quack/', ''),
 
2530
            'success', ('ok',))
 
2531
        # Create a fake real repository for insert_stream to fall back on, so
 
2532
        # that we can directly see the records the RemoteSink passes to the
 
2533
        # real sink.
 
2534
        class FakeRealSink:
 
2535
            def __init__(self):
 
2536
                self.records = []
 
2537
            def insert_stream(self, stream, src_format, resume_tokens):
 
2538
                for substream_kind, substream in stream:
 
2539
                    self.records.append(
 
2540
                        (substream_kind, [record.key for record in substream]))
 
2541
                return ['fake tokens'], ['fake missing keys']
 
2542
        fake_real_sink = FakeRealSink()
 
2543
        class FakeRealRepository:
 
2544
            def _get_sink(self):
 
2545
                return fake_real_sink
 
2546
            def is_in_write_group(self):
 
2547
                return False
 
2548
            def refresh_data(self):
 
2549
                return True
 
2550
        repo._real_repository = FakeRealRepository()
 
2551
        sink = repo._get_sink()
 
2552
        fmt = repository.RepositoryFormat.get_default_format()
 
2553
        stream = self.make_stream_with_inv_deltas(fmt)
 
2554
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
 
2555
        # Every record from the first inventory delta should have been sent to
 
2556
        # the VFS sink.
 
2557
        expected_records = [
 
2558
            ('inventory-deltas', [('rev2',), ('rev3',)]),
 
2559
            ('texts', [('some-rev', 'some-file')])]
 
2560
        self.assertEqual(expected_records, fake_real_sink.records)
 
2561
        # The return values from the real sink's insert_stream are propagated
 
2562
        # back to the original caller.
 
2563
        self.assertEqual(['fake tokens'], resume_tokens)
 
2564
        self.assertEqual(['fake missing keys'], missing_keys)
 
2565
        self.assertFinished(client)
 
2566
 
 
2567
    def make_stream_with_inv_deltas(self, fmt):
 
2568
        """Make a simple stream with an inventory delta followed by more
 
2569
        records and more substreams to test that all records and substreams
 
2570
        from that point on are used.
 
2571
 
 
2572
        This sends, in order:
 
2573
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
 
2574
             inventory-deltas.
 
2575
           * texts substream: (some-rev, some-file)
 
2576
        """
 
2577
        # Define a stream using generators so that it isn't rewindable.
 
2578
        inv = inventory.Inventory(revision_id='rev1')
 
2579
        inv.root.revision = 'rev1'
 
2580
        def stream_with_inv_delta():
 
2581
            yield ('inventories', inventories_substream())
 
2582
            yield ('inventory-deltas', inventory_delta_substream())
 
2583
            yield ('texts', [
 
2584
                versionedfile.FulltextContentFactory(
 
2585
                    ('some-rev', 'some-file'), (), None, 'content')])
 
2586
        def inventories_substream():
 
2587
            # An empty inventory fulltext.  This will be streamed normally.
 
2588
            text = fmt._serializer.write_inventory_to_string(inv)
 
2589
            yield versionedfile.FulltextContentFactory(
 
2590
                ('rev1',), (), None, text)
 
2591
        def inventory_delta_substream():
 
2592
            # An inventory delta.  This can't be streamed via this verb, so it
 
2593
            # will trigger a fallback to VFS insert_stream.
 
2594
            entry = inv.make_entry(
 
2595
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
 
2596
            entry.revision = 'ghost'
 
2597
            delta = [(None, 'newdir', 'newdir-id', entry)]
 
2598
            serializer = inventory_delta.InventoryDeltaSerializer(
 
2599
                versioned_root=True, tree_references=False)
 
2600
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
 
2601
            yield versionedfile.ChunkedContentFactory(
 
2602
                ('rev2',), (('rev1',)), None, lines)
 
2603
            # Another delta.
 
2604
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
 
2605
            yield versionedfile.ChunkedContentFactory(
 
2606
                ('rev3',), (('rev1',)), None, lines)
 
2607
        return stream_with_inv_delta()
 
2608
 
 
2609
 
 
2610
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
 
2611
 
 
2612
    def test_unlocked_repo(self):
 
2613
        transport_path = 'quack'
 
2614
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2615
        client.add_expected_call(
 
2616
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2617
            'success', ('ok',))
 
2618
        client.add_expected_call(
 
2619
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2620
            'success', ('ok',))
 
2621
        self.checkInsertEmptyStream(repo, client)
 
2622
 
 
2623
    def test_locked_repo_with_no_lock_token(self):
 
2624
        transport_path = 'quack'
 
2625
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2626
        client.add_expected_call(
 
2627
            'Repository.lock_write', ('quack/', ''),
 
2628
            'success', ('ok', ''))
 
2629
        client.add_expected_call(
 
2630
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2631
            'success', ('ok',))
 
2632
        client.add_expected_call(
 
2633
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2634
            'success', ('ok',))
 
2635
        repo.lock_write()
 
2636
        self.checkInsertEmptyStream(repo, client)
 
2637
 
 
2638
    def test_locked_repo_with_lock_token(self):
 
2639
        transport_path = 'quack'
 
2640
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2641
        client.add_expected_call(
 
2642
            'Repository.lock_write', ('quack/', ''),
 
2643
            'success', ('ok', 'a token'))
 
2644
        client.add_expected_call(
 
2645
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2646
            'success', ('ok',))
 
2647
        client.add_expected_call(
 
2648
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2649
            'success', ('ok',))
 
2650
        repo.lock_write()
 
2651
        self.checkInsertEmptyStream(repo, client)
2279
2652
 
2280
2653
 
2281
2654
class TestRepositoryTarball(TestRemoteRepository):
2317
2690
    """RemoteRepository.copy_content_into optimizations"""
2318
2691
 
2319
2692
    def test_copy_content_remote_to_local(self):
2320
 
        self.transport_server = server.SmartTCPServer_for_testing
 
2693
        self.transport_server = test_server.SmartTCPServer_for_testing
2321
2694
        src_repo = self.make_repository('repo1')
2322
2695
        src_repo = repository.Repository.open(self.get_url('repo1'))
2323
2696
        # At the moment the tarball-based copy_content_into can't write back
2471
2844
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2472
2845
        self.assertEqual(expected_error, translated_error)
2473
2846
 
 
2847
    def test_nobranch_one_arg(self):
 
2848
        bzrdir = self.make_bzrdir('')
 
2849
        translated_error = self.translateTuple(
 
2850
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
 
2851
        expected_error = errors.NotBranchError(
 
2852
            path=bzrdir.root_transport.base,
 
2853
            detail='extra detail')
 
2854
        self.assertEqual(expected_error, translated_error)
 
2855
 
2474
2856
    def test_LockContention(self):
2475
2857
        translated_error = self.translateTuple(('LockContention',))
2476
2858
        expected_error = errors.LockContention('(remote lock)')
2516
2898
        expected_error = errors.ReadError(path)
2517
2899
        self.assertEqual(expected_error, translated_error)
2518
2900
 
 
2901
    def test_IncompatibleRepositories(self):
 
2902
        translated_error = self.translateTuple(('IncompatibleRepositories',
 
2903
            "repo1", "repo2", "details here"))
 
2904
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
 
2905
            "details here")
 
2906
        self.assertEqual(expected_error, translated_error)
 
2907
 
2519
2908
    def test_PermissionDenied_no_args(self):
2520
2909
        path = 'a path'
2521
2910
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2582
2971
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2583
2972
        # been muttered to the log file for developer to look at.
2584
2973
        self.assertContainsRe(
2585
 
            self._get_log(keep_log_file=True),
 
2974
            self.get_log(),
2586
2975
            "Missing key 'branch' in context")
2587
2976
 
2588
2977
    def test_path_missing(self):
2596
2985
        self.assertEqual(server_error, translated_error)
2597
2986
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2598
2987
        # been muttered to the log file for developer to look at.
2599
 
        self.assertContainsRe(
2600
 
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
 
2988
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
2601
2989
 
2602
2990
 
2603
2991
class TestStacking(tests.TestCaseWithTransport):
2621
3009
        stacked_branch = self.make_branch('stacked', format='1.9')
2622
3010
        stacked_branch.set_stacked_on_url('../base')
2623
3011
        # start a server looking at this
2624
 
        smart_server = server.SmartTCPServer_for_testing()
2625
 
        smart_server.setUp()
2626
 
        self.addCleanup(smart_server.tearDown)
 
3012
        smart_server = test_server.SmartTCPServer_for_testing()
 
3013
        self.start_server(smart_server)
2627
3014
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2628
3015
        # can get its branch and repository
2629
3016
        remote_branch = remote_bzrdir.open_branch()
2651
3038
        tree1.commit('rev1', rev_id='rev1')
2652
3039
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2653
3040
            ).open_workingtree()
2654
 
        tree2.commit('local changes make me feel good.')
 
3041
        local_tree = tree2.branch.create_checkout('local')
 
3042
        local_tree.commit('local changes make me feel good.')
2655
3043
        branch2 = Branch.open(self.get_url('tree2'))
2656
3044
        branch2.lock_read()
2657
3045
        self.addCleanup(branch2.unlock)
2727
3115
            _, stacked = self.prepare_stacked_remote_branch()
2728
3116
            tree = stacked.bzrdir.sprout('tree3', stacked=True
2729
3117
                ).open_workingtree()
2730
 
            tree.commit('more local changes are better')
 
3118
            local_tree = tree.branch.create_checkout('local-tree3')
 
3119
            local_tree.commit('more local changes are better')
2731
3120
            branch = Branch.open(self.get_url('tree3'))
2732
3121
            branch.lock_read()
 
3122
            self.addCleanup(branch.unlock)
2733
3123
            return None, branch
2734
3124
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
2735
3125
            branch_factory=make_stacked_stacked)
2744
3134
        # stacked upon sources in topological order.
2745
3135
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
2746
3136
        self.assertEqual(expected_revs, rev_ord)
2747
 
        # Getting topological sort requires VFS calls still
2748
 
        self.assertLength(12, self.hpss_calls)
 
3137
        # Getting topological sort requires VFS calls still - one of which is
 
3138
        # pushing up from the bound branch.
 
3139
        self.assertLength(13, self.hpss_calls)
2749
3140
 
2750
3141
    def test_stacked_get_stream_groupcompress(self):
2751
3142
        # Repository._get_source.get_stream() from a stacked repository with
2780
3171
        super(TestRemoteBranchEffort, self).setUp()
2781
3172
        # Create a smart server that publishes whatever the backing VFS server
2782
3173
        # does.
2783
 
        self.smart_server = server.SmartTCPServer_for_testing()
2784
 
        self.smart_server.setUp(self.get_server())
2785
 
        self.addCleanup(self.smart_server.tearDown)
 
3174
        self.smart_server = test_server.SmartTCPServer_for_testing()
 
3175
        self.start_server(self.smart_server, self.get_server())
2786
3176
        # Log all HPSS calls into self.hpss_calls.
2787
3177
        _SmartClient.hooks.install_named_hook(
2788
3178
            'call', self.capture_hpss_call, None)