~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: 2011-08-17 18:13:57 UTC
  • mfrom: (5268.7.29 transport-segments)
  • Revision ID: pqm@pqm.ubuntu.com-20110817181357-y5q5eth1hk8bl3om
(jelmer) Allow specifying the colocated branch to use in the branch URL,
 and retrieving the branch name using ControlDir._get_selected_branch.
 (Jelmer Vernooij)

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-2011 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
30
30
    branch,
31
31
    bzrdir,
32
32
    config,
 
33
    controldir,
33
34
    errors,
34
 
    graph,
 
35
    graph as _mod_graph,
35
36
    inventory,
36
37
    inventory_delta,
37
 
    pack,
38
38
    remote,
39
39
    repository,
40
40
    tests,
 
41
    transport,
41
42
    treebuilder,
42
 
    urlutils,
43
43
    versionedfile,
44
44
    )
45
45
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
46
from bzrlib.bzrdir import (
 
47
    BzrDir,
 
48
    BzrDirFormat,
 
49
    RemoteBzrProber,
 
50
    )
47
51
from bzrlib.remote import (
48
52
    RemoteBranch,
49
53
    RemoteBranchFormat,
52
56
    RemoteRepository,
53
57
    RemoteRepositoryFormat,
54
58
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
 
59
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
56
60
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import server, medium
 
61
from bzrlib.smart import medium, request
58
62
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
63
from bzrlib.smart.repository import (
 
64
    SmartServerRepositoryGetParentMap,
 
65
    SmartServerRepositoryGetStream_1_19,
 
66
    )
60
67
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
 
68
    test_server,
64
69
    )
65
 
from bzrlib.transport import get_transport
 
70
from bzrlib.tests.scenarios import load_tests_apply_scenarios
66
71
from bzrlib.transport.memory import MemoryTransport
67
72
from bzrlib.transport.remote import (
68
73
    RemoteTransport,
69
74
    RemoteSSHTransport,
70
75
    RemoteTCPTransport,
71
 
)
72
 
 
73
 
def load_tests(standard_tests, module, loader):
74
 
    to_adapt, result = split_suite_by_condition(
75
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
76
 
    smart_server_version_scenarios = [
 
76
    )
 
77
 
 
78
 
 
79
load_tests = load_tests_apply_scenarios
 
80
 
 
81
 
 
82
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
83
 
 
84
    scenarios = [
77
85
        ('HPSS-v2',
78
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
 
86
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
79
87
        ('HPSS-v3',
80
 
            {'transport_server': server.SmartTCPServer_for_testing})]
81
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
82
 
 
83
 
 
84
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
88
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
89
 
85
90
 
86
91
    def setUp(self):
87
92
        super(BasicRemoteObjectTests, self).setUp()
88
93
        self.transport = self.get_transport()
89
94
        # make a branch that can be opened over the smart transport
90
95
        self.local_wt = BzrDir.create_standalone_workingtree('.')
91
 
 
92
 
    def tearDown(self):
93
 
        self.transport.disconnect()
94
 
        tests.TestCaseWithTransport.tearDown(self)
 
96
        self.addCleanup(self.transport.disconnect)
95
97
 
96
98
    def test_create_remote_bzrdir(self):
97
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
99
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
98
100
        self.assertIsInstance(b, BzrDir)
99
101
 
100
102
    def test_open_remote_branch(self):
101
103
        # open a standalone branch in the working directory
102
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
104
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
103
105
        branch = b.open_branch()
104
106
        self.assertIsInstance(branch, Branch)
105
107
 
121
123
    def test_find_correct_format(self):
122
124
        """Should open a RemoteBzrDir over a RemoteTransport"""
123
125
        fmt = BzrDirFormat.find_format(self.transport)
124
 
        self.assertTrue(RemoteBzrDirFormat
125
 
                        in BzrDirFormat._control_server_formats)
126
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
126
        self.assertTrue(bzrdir.RemoteBzrProber
 
127
                        in controldir.ControlDirFormat._server_probers)
 
128
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
127
129
 
128
130
    def test_open_detected_smart_format(self):
129
131
        fmt = BzrDirFormat.find_format(self.transport)
358
360
        a given client_base and transport_base.
359
361
        """
360
362
        client_medium = medium.SmartClientMedium(client_base)
361
 
        transport = get_transport(transport_base)
362
 
        result = client_medium.remote_path_from_transport(transport)
 
363
        t = transport.get_transport(transport_base)
 
364
        result = client_medium.remote_path_from_transport(t)
363
365
        self.assertEqual(expected, result)
364
366
 
365
367
    def test_remote_path_from_transport(self):
376
378
        a given transport_base and relpath of that transport.  (Note that
377
379
        HttpTransportBase is a subclass of SmartClientMedium)
378
380
        """
379
 
        base_transport = get_transport(transport_base)
 
381
        base_transport = transport.get_transport(transport_base)
380
382
        client_medium = base_transport.get_smart_medium()
381
383
        cloned_transport = base_transport.clone(relpath)
382
384
        result = client_medium.remote_path_from_transport(cloned_transport)
417
419
        # Calling _remember_remote_is_before again with a lower value works.
418
420
        client_medium._remember_remote_is_before((1, 5))
419
421
        self.assertTrue(client_medium._is_remote_before((1, 5)))
420
 
        # You cannot call _remember_remote_is_before with a larger value.
421
 
        self.assertRaises(
422
 
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
 
422
        # If you call _remember_remote_is_before with a higher value it logs a
 
423
        # warning, and continues to remember the lower value.
 
424
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
 
425
        client_medium._remember_remote_is_before((1, 9))
 
426
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
 
427
        self.assertTrue(client_medium._is_remote_before((1, 5)))
423
428
 
424
429
 
425
430
class TestBzrDirCloningMetaDir(TestRemote):
446
451
        client.add_expected_call(
447
452
            'BzrDir.open_branchV3', ('quack/',),
448
453
            'success', ('ref', self.get_url('referenced'))),
449
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
454
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
450
455
            _client=client)
451
456
        result = a_bzrdir.cloning_metadir()
452
457
        # We should have got a control dir matching the referenced branch.
465
470
        client.add_expected_call(
466
471
            'BzrDir.cloning_metadir', ('quack/', 'False'),
467
472
            'success', (control_name, '', ('branch', ''))),
468
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
473
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
469
474
            _client=client)
470
475
        result = a_bzrdir.cloning_metadir()
471
476
        # We should have got a reference control dir with default branch and
491
496
        client.add_expected_call(
492
497
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
493
498
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
494
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
499
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
495
500
        self.assertFinished(client)
496
501
 
497
502
    def test_present_without_workingtree(self):
498
503
        client, transport = self.make_fake_client_and_transport()
499
504
        client.add_expected_call(
500
505
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
501
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
506
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
502
507
            _client=client, _force_probe=True)
503
508
        self.assertIsInstance(bd, RemoteBzrDir)
504
509
        self.assertFalse(bd.has_workingtree())
509
514
        client, transport = self.make_fake_client_and_transport()
510
515
        client.add_expected_call(
511
516
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
512
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
517
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
513
518
            _client=client, _force_probe=True)
514
519
        self.assertIsInstance(bd, RemoteBzrDir)
515
520
        self.assertTrue(bd.has_workingtree())
522
527
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
523
528
        client.add_expected_call(
524
529
            'BzrDir.open', ('quack/',), 'success', ('yes',))
525
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
530
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
531
            _client=client, _force_probe=True)
 
532
        self.assertIsInstance(bd, RemoteBzrDir)
 
533
        self.assertFinished(client)
 
534
 
 
535
    def test_backwards_compat_hpss_v2(self):
 
536
        client, transport = self.make_fake_client_and_transport()
 
537
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
538
        # server: upon first RPC call detect the protocol version, and because
 
539
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
540
        # continuing with the RPC.
 
541
        orig_check_call = client._check_call
 
542
        def check_call(method, args):
 
543
            client._medium._protocol_version = 2
 
544
            client._medium._remember_remote_is_before((1, 6))
 
545
            client._check_call = orig_check_call
 
546
            client._check_call(method, args)
 
547
        client._check_call = check_call
 
548
        client.add_expected_call(
 
549
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
550
        client.add_expected_call(
 
551
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
552
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
526
553
            _client=client, _force_probe=True)
527
554
        self.assertIsInstance(bd, RemoteBzrDir)
528
555
        self.assertFinished(client)
559
586
        client.add_expected_call(
560
587
            'Branch.get_stacked_on_url', ('quack/',),
561
588
            'error', ('NotStacked',))
562
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
589
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
563
590
            _client=client)
564
591
        result = bzrdir.open_branch()
565
592
        self.assertIsInstance(result, RemoteBranch)
572
599
        transport = transport.clone('quack')
573
600
        client = FakeClient(transport.base)
574
601
        client.add_error_response('nobranch')
575
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
602
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
576
603
            _client=client)
577
604
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
578
605
        self.assertEqual(
583
610
        # _get_tree_branch is a form of open_branch, but it should only ask for
584
611
        # branch opening, not any other network requests.
585
612
        calls = []
586
 
        def open_branch():
 
613
        def open_branch(name=None):
587
614
            calls.append("Called")
588
615
            return "a-branch"
589
616
        transport = MemoryTransport()
590
617
        # no requests on the network - catches other api calls being made.
591
618
        client = FakeClient(transport.base)
592
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
619
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
593
620
            _client=client)
594
621
        # patch the open_branch call to record that it was called.
595
622
        bzrdir.open_branch = open_branch
614
641
        client.add_expected_call(
615
642
            'Branch.get_stacked_on_url', ('~hello/',),
616
643
            'error', ('NotStacked',))
617
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
644
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
618
645
            _client=client)
619
646
        result = bzrdir.open_branch()
620
647
        self.assertFinished(client)
637
664
        client.add_success_response(
638
665
            'ok', '', rich_response, subtree_response, external_lookup,
639
666
            network_name)
640
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
667
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
641
668
            _client=client)
642
669
        result = bzrdir.open_repository()
643
670
        self.assertEqual(
660
687
        old.
661
688
        """
662
689
        self.assertRaises(errors.NotBranchError,
663
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
690
            RemoteBzrProber.probe_transport, OldServerTransport())
664
691
 
665
692
 
666
693
class TestBzrDirCreateBranch(TestRemote):
689
716
            'BzrDir.create_branch', ('quack/', network_name),
690
717
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
691
718
            reference_repo_name))
692
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
719
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
693
720
            _client=client)
694
721
        branch = a_bzrdir.create_branch()
695
722
        # We should have got a remote branch
698
725
        format = branch._format
699
726
        self.assertEqual(network_name, format.network_name())
700
727
 
 
728
    def test_already_open_repo_and_reused_medium(self):
 
729
        """Bug 726584: create_branch(..., repository=repo) should work
 
730
        regardless of what the smart medium's base URL is.
 
731
        """
 
732
        self.transport_server = test_server.SmartTCPServer_for_testing
 
733
        transport = self.get_transport('.')
 
734
        repo = self.make_repository('quack')
 
735
        # Client's medium rooted a transport root (not at the bzrdir)
 
736
        client = FakeClient(transport.base)
 
737
        transport = transport.clone('quack')
 
738
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
739
        reference_format = reference_bzrdir_format.get_branch_format()
 
740
        network_name = reference_format.network_name()
 
741
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
742
        reference_repo_name = reference_repo_fmt.network_name()
 
743
        client.add_expected_call(
 
744
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
745
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
746
            reference_repo_name))
 
747
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
748
            _client=client)
 
749
        branch = a_bzrdir.create_branch(repository=repo)
 
750
        # We should have got a remote branch
 
751
        self.assertIsInstance(branch, remote.RemoteBranch)
 
752
        # its format should have the settings from the response
 
753
        format = branch._format
 
754
        self.assertEqual(network_name, format.network_name())
 
755
 
701
756
 
702
757
class TestBzrDirCreateRepository(TestRemote):
703
758
 
724
779
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
725
780
                'False'),
726
781
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
727
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
782
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
728
783
            _client=client)
729
784
        repo = a_bzrdir.create_repository()
730
785
        # We should have got a remote repository
759
814
        client.add_success_response('stat', '0', '65535')
760
815
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
761
816
            _client=client)
762
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
817
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
763
818
            _client=client)
764
819
        repo = bzrdir.open_repository()
765
820
        self.assertEqual(
792
847
        client.add_success_response('stat', '0', '65535')
793
848
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
794
849
            _client=client)
795
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
850
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
796
851
            _client=client)
797
852
        repo = bzrdir.open_repository()
798
853
        self.assertEqual(
813
868
        transport = transport.clone('quack')
814
869
        client = FakeClient(transport.base)
815
870
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
816
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
871
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
817
872
            _client=client)
818
873
        repo = bzrdir.open_repository()
819
874
        self.assertEqual(
826
881
 
827
882
    def test_success(self):
828
883
        """Simple test for typical successful call."""
829
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
884
        fmt = RemoteBzrDirFormat()
830
885
        default_format_name = BzrDirFormat.get_default_format().network_name()
831
886
        transport = self.get_transport()
832
887
        client = FakeClient(transport.base)
848
903
        """Error responses are translated, e.g. 'PermissionDenied' raises the
849
904
        corresponding error from the client.
850
905
        """
851
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
906
        fmt = RemoteBzrDirFormat()
852
907
        default_format_name = BzrDirFormat.get_default_format().network_name()
853
908
        transport = self.get_transport()
854
909
        client = FakeClient(transport.base)
872
927
        """Integration test for error translation."""
873
928
        transport = self.make_smart_server('foo')
874
929
        transport = transport.clone('no-such-path')
875
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
930
        fmt = RemoteBzrDirFormat()
876
931
        err = self.assertRaises(errors.NoSuchFile,
877
932
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
878
933
 
909
964
 
910
965
    def make_remote_bzrdir(self, transport, client):
911
966
        """Make a RemotebzrDir using 'client' as the _client."""
912
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
967
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
913
968
            _client=client)
914
969
 
915
970
 
1117
1172
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1118
1173
 
1119
1174
 
 
1175
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1176
 
 
1177
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1178
        transport = MemoryTransport()
 
1179
        client = FakeClient(transport.base)
 
1180
        client.add_expected_call(
 
1181
            'Branch.get_stacked_on_url', ('quack/',),
 
1182
            'error', ('NotStacked',))
 
1183
        client.add_expected_call(
 
1184
            'Branch.last_revision_info', ('quack/',),
 
1185
            'success', ('ok', '1', 'rev-tip'))
 
1186
        client.add_expected_call(
 
1187
            'Branch.get_config_file', ('quack/',),
 
1188
            'success', ('ok',), '')
 
1189
        transport.mkdir('quack')
 
1190
        transport = transport.clone('quack')
 
1191
        branch = self.make_remote_branch(transport, client)
 
1192
        result = branch.heads_to_fetch()
 
1193
        self.assertFinished(client)
 
1194
        self.assertEqual((set(['rev-tip']), set()), result)
 
1195
 
 
1196
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1197
        transport = MemoryTransport()
 
1198
        client = FakeClient(transport.base)
 
1199
        client.add_expected_call(
 
1200
            'Branch.get_stacked_on_url', ('quack/',),
 
1201
            'error', ('NotStacked',))
 
1202
        client.add_expected_call(
 
1203
            'Branch.last_revision_info', ('quack/',),
 
1204
            'success', ('ok', '1', 'rev-tip'))
 
1205
        client.add_expected_call(
 
1206
            'Branch.get_config_file', ('quack/',),
 
1207
            'success', ('ok',), 'branch.fetch_tags = True')
 
1208
        # XXX: this will break if the default format's serialization of tags
 
1209
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1210
        client.add_expected_call(
 
1211
            'Branch.get_tags_bytes', ('quack/',),
 
1212
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1213
        transport.mkdir('quack')
 
1214
        transport = transport.clone('quack')
 
1215
        branch = self.make_remote_branch(transport, client)
 
1216
        result = branch.heads_to_fetch()
 
1217
        self.assertFinished(client)
 
1218
        self.assertEqual(
 
1219
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1220
 
 
1221
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1222
        transport = MemoryTransport()
 
1223
        client = FakeClient(transport.base)
 
1224
        client.add_expected_call(
 
1225
            'Branch.get_stacked_on_url', ('quack/',),
 
1226
            'error', ('NotStacked',))
 
1227
        client.add_expected_call(
 
1228
            'Branch.heads_to_fetch', ('quack/',),
 
1229
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1230
        transport.mkdir('quack')
 
1231
        transport = transport.clone('quack')
 
1232
        branch = self.make_remote_branch(transport, client)
 
1233
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1234
        result = branch.heads_to_fetch()
 
1235
        self.assertFinished(client)
 
1236
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1237
 
 
1238
    def make_branch_with_tags(self):
 
1239
        self.setup_smart_server_with_call_log()
 
1240
        # Make a branch with a single revision.
 
1241
        builder = self.make_branch_builder('foo')
 
1242
        builder.start_series()
 
1243
        builder.build_snapshot('tip', None, [
 
1244
            ('add', ('', 'root-id', 'directory', ''))])
 
1245
        builder.finish_series()
 
1246
        branch = builder.get_branch()
 
1247
        # Add two tags to that branch
 
1248
        branch.tags.set_tag('tag-1', 'rev-1')
 
1249
        branch.tags.set_tag('tag-2', 'rev-2')
 
1250
        return branch
 
1251
 
 
1252
    def test_backwards_compatible(self):
 
1253
        branch = self.make_branch_with_tags()
 
1254
        c = branch.get_config()
 
1255
        c.set_user_option('branch.fetch_tags', 'True')
 
1256
        self.addCleanup(branch.lock_read().unlock)
 
1257
        # Disable the heads_to_fetch verb
 
1258
        verb = 'Branch.heads_to_fetch'
 
1259
        self.disable_verb(verb)
 
1260
        self.reset_smart_call_log()
 
1261
        result = branch.heads_to_fetch()
 
1262
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1263
        self.assertEqual(
 
1264
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1265
             'Branch.get_tags_bytes'],
 
1266
            [call.call.method for call in self.hpss_calls])
 
1267
 
 
1268
    def test_backwards_compatible_no_tags(self):
 
1269
        branch = self.make_branch_with_tags()
 
1270
        c = branch.get_config()
 
1271
        c.set_user_option('branch.fetch_tags', 'False')
 
1272
        self.addCleanup(branch.lock_read().unlock)
 
1273
        # Disable the heads_to_fetch verb
 
1274
        verb = 'Branch.heads_to_fetch'
 
1275
        self.disable_verb(verb)
 
1276
        self.reset_smart_call_log()
 
1277
        result = branch.heads_to_fetch()
 
1278
        self.assertEqual((set(['tip']), set()), result)
 
1279
        self.assertEqual(
 
1280
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1281
            [call.call.method for call in self.hpss_calls])
 
1282
 
 
1283
 
1120
1284
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1121
1285
 
1122
1286
    def test_empty_branch(self):
1177
1341
        client.add_expected_call(
1178
1342
            'Branch.get_stacked_on_url', ('stacked/',),
1179
1343
            'success', ('ok', vfs_url))
1180
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1344
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1181
1345
            _client=client)
1182
1346
        repo_fmt = remote.RemoteRepositoryFormat()
1183
1347
        repo_fmt._custom_format = stacked_branch.repository._format
1210
1374
        # this will also do vfs access, but that goes direct to the transport
1211
1375
        # and isn't seen by the FakeClient.
1212
1376
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1213
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1377
            RemoteBzrDirFormat(), _client=client)
1214
1378
        branch = bzrdir.open_branch()
1215
1379
        result = branch.get_stacked_on_url()
1216
1380
        self.assertEqual('../base', result)
1222
1386
            len(branch.repository._real_repository._fallback_repositories))
1223
1387
 
1224
1388
    def test_get_stacked_on_real_branch(self):
1225
 
        base_branch = self.make_branch('base', format='1.6')
1226
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1389
        base_branch = self.make_branch('base')
 
1390
        stacked_branch = self.make_branch('stacked')
1227
1391
        stacked_branch.set_stacked_on_url('../base')
1228
1392
        reference_format = self.get_repo_format()
1229
1393
        network_name = reference_format.network_name()
1234
1398
            'success', ('branch', branch_network_name))
1235
1399
        client.add_expected_call(
1236
1400
            'BzrDir.find_repositoryV3', ('stacked/',),
1237
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1401
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1238
1402
        # called twice, once from constructor and then again by us
1239
1403
        client.add_expected_call(
1240
1404
            'Branch.get_stacked_on_url', ('stacked/',),
1243
1407
            'Branch.get_stacked_on_url', ('stacked/',),
1244
1408
            'success', ('ok', '../base'))
1245
1409
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1246
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1410
            RemoteBzrDirFormat(), _client=client)
1247
1411
        branch = bzrdir.open_branch()
1248
1412
        result = branch.get_stacked_on_url()
1249
1413
        self.assertEqual('../base', result)
1257
1421
class TestBranchSetLastRevision(RemoteBranchTestCase):
1258
1422
 
1259
1423
    def test_set_empty(self):
1260
 
        # set_revision_history([]) is translated to calling
 
1424
        # _set_last_revision_info('null:') is translated to calling
1261
1425
        # Branch.set_last_revision(path, '') on the wire.
1262
1426
        transport = MemoryTransport()
1263
1427
        transport.mkdir('branch')
1285
1449
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1286
1450
        branch._ensure_real = lambda: None
1287
1451
        branch.lock_write()
1288
 
        result = branch.set_revision_history([])
 
1452
        result = branch._set_last_revision(NULL_REVISION)
1289
1453
        branch.unlock()
1290
1454
        self.assertEqual(None, result)
1291
1455
        self.assertFinished(client)
1292
1456
 
1293
1457
    def test_set_nonempty(self):
1294
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1458
        # set_last_revision_info(N, rev-idN) is translated to calling
1295
1459
        # Branch.set_last_revision(path, rev-idN) on the wire.
1296
1460
        transport = MemoryTransport()
1297
1461
        transport.mkdir('branch')
1323
1487
        branch._ensure_real = lambda: None
1324
1488
        # Lock the branch, reset the record of remote calls.
1325
1489
        branch.lock_write()
1326
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1490
        result = branch._set_last_revision('rev-id2')
1327
1491
        branch.unlock()
1328
1492
        self.assertEqual(None, result)
1329
1493
        self.assertFinished(client)
1359
1523
        branch = self.make_remote_branch(transport, client)
1360
1524
        branch.lock_write()
1361
1525
        self.assertRaises(
1362
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1526
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1363
1527
        branch.unlock()
1364
1528
        self.assertFinished(client)
1365
1529
 
1396
1560
        branch._ensure_real = lambda: None
1397
1561
        branch.lock_write()
1398
1562
        # The 'TipChangeRejected' error response triggered by calling
1399
 
        # set_revision_history causes a TipChangeRejected exception.
 
1563
        # set_last_revision_info causes a TipChangeRejected exception.
1400
1564
        err = self.assertRaises(
1401
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1565
            errors.TipChangeRejected,
 
1566
            branch._set_last_revision, 'rev-id')
1402
1567
        # The UTF-8 message from the response has been decoded into a unicode
1403
1568
        # object.
1404
1569
        self.assertIsInstance(err.msg, unicode)
1592
1757
    def test_get_multi_line_branch_conf(self):
1593
1758
        # Make sure that multiple-line branch.conf files are supported
1594
1759
        #
1595
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1760
        # https://bugs.launchpad.net/bzr/+bug/354075
1596
1761
        client = FakeClient()
1597
1762
        client.add_expected_call(
1598
1763
            'Branch.get_stacked_on_url', ('memory:///',),
1626
1791
        branch.unlock()
1627
1792
        self.assertFinished(client)
1628
1793
 
 
1794
    def test_set_option_with_dict(self):
 
1795
        client = FakeClient()
 
1796
        client.add_expected_call(
 
1797
            'Branch.get_stacked_on_url', ('memory:///',),
 
1798
            'error', ('NotStacked',),)
 
1799
        client.add_expected_call(
 
1800
            'Branch.lock_write', ('memory:///', '', ''),
 
1801
            'success', ('ok', 'branch token', 'repo token'))
 
1802
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1803
        client.add_expected_call(
 
1804
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1805
            'repo token', encoded_dict_value, 'foo', ''),
 
1806
            'success', ())
 
1807
        client.add_expected_call(
 
1808
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1809
            'success', ('ok',))
 
1810
        transport = MemoryTransport()
 
1811
        branch = self.make_remote_branch(transport, client)
 
1812
        branch.lock_write()
 
1813
        config = branch._get_config()
 
1814
        config.set_option(
 
1815
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1816
            'foo')
 
1817
        branch.unlock()
 
1818
        self.assertFinished(client)
 
1819
 
1629
1820
    def test_backwards_compat_set_option(self):
1630
1821
        self.setup_smart_server_with_call_log()
1631
1822
        branch = self.make_branch('.')
1638
1829
        self.assertLength(10, self.hpss_calls)
1639
1830
        self.assertEqual('value', branch._get_config().get_option('name'))
1640
1831
 
 
1832
    def test_backwards_compat_set_option_with_dict(self):
 
1833
        self.setup_smart_server_with_call_log()
 
1834
        branch = self.make_branch('.')
 
1835
        verb = 'Branch.set_config_option_dict'
 
1836
        self.disable_verb(verb)
 
1837
        branch.lock_write()
 
1838
        self.addCleanup(branch.unlock)
 
1839
        self.reset_smart_call_log()
 
1840
        config = branch._get_config()
 
1841
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
1842
        config.set_option(value_dict, 'name')
 
1843
        self.assertLength(10, self.hpss_calls)
 
1844
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
1845
 
1641
1846
 
1642
1847
class TestBranchLockWrite(RemoteBranchTestCase):
1643
1848
 
1779
1984
        client = FakeClient(transport.base)
1780
1985
        transport = transport.clone(transport_path)
1781
1986
        # we do not want bzrdir to make any remote calls
1782
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1987
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1783
1988
            _client=False)
1784
1989
        repo = RemoteRepository(bzrdir, None, _client=client)
1785
1990
        return repo, client
1793
1998
 
1794
1999
    def test_get_format_description(self):
1795
2000
        remote_format = RemoteBranchFormat()
1796
 
        real_format = branch.BranchFormat.get_default_format()
 
2001
        real_format = branch.format_registry.get_default()
1797
2002
        remote_format._network_name = real_format.network_name()
1798
2003
        self.assertEqual(remoted_description(real_format),
1799
2004
            remote_format.get_format_description())
1802
2007
class TestRepositoryFormat(TestRemoteRepository):
1803
2008
 
1804
2009
    def test_fast_delta(self):
1805
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2010
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1806
2011
        true_format = RemoteRepositoryFormat()
1807
2012
        true_format._network_name = true_name
1808
2013
        self.assertEqual(True, true_format.fast_deltas)
1809
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2014
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1810
2015
        false_format = RemoteRepositoryFormat()
1811
2016
        false_format._network_name = false_name
1812
2017
        self.assertEqual(False, false_format.fast_deltas)
1813
2018
 
1814
2019
    def test_get_format_description(self):
1815
2020
        remote_repo_format = RemoteRepositoryFormat()
1816
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2021
        real_format = repository.format_registry.get_default()
1817
2022
        remote_repo_format._network_name = real_format.network_name()
1818
2023
        self.assertEqual(remoted_description(real_format),
1819
2024
            remote_repo_format.get_format_description())
2074
2279
 
2075
2280
    def test_allows_new_revisions(self):
2076
2281
        """get_parent_map's results can be updated by commit."""
2077
 
        smart_server = server.SmartTCPServer_for_testing()
 
2282
        smart_server = test_server.SmartTCPServer_for_testing()
2078
2283
        self.start_server(smart_server)
2079
2284
        self.make_branch('branch')
2080
2285
        branch = Branch.open(smart_server.get_url() + '/branch')
2190
2395
        """
2191
2396
        # Make a repo with a fallback repo, both using a FakeClient.
2192
2397
        format = remote.response_tuple_to_repo_format(
2193
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2398
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2194
2399
        repo, client = self.setup_fake_client_and_repository('quack')
2195
2400
        repo._format = format
2196
2401
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2197
2402
            'fallback')
2198
2403
        fallback_repo._client = client
 
2404
        fallback_repo._format = format
2199
2405
        repo.add_fallback_repository(fallback_repo)
2200
2406
        # First the client should ask the primary repo
2201
2407
        client.add_expected_call(
2230
2436
        self.setup_smart_server_with_call_log()
2231
2437
        tree = self.make_branch_and_memory_tree('.')
2232
2438
        tree.lock_write()
 
2439
        tree.add('')
2233
2440
        rev1 = tree.commit('First')
2234
2441
        rev2 = tree.commit('Second')
2235
2442
        tree.unlock()
2274
2481
        transport_path = 'quack'
2275
2482
        repo, client = self.setup_fake_client_and_repository(transport_path)
2276
2483
        client.add_success_response('ok', 'a token')
2277
 
        result = repo.lock_write()
 
2484
        token = repo.lock_write().repository_token
2278
2485
        self.assertEqual(
2279
2486
            [('call', 'Repository.lock_write', ('quack/', ''))],
2280
2487
            client._calls)
2281
 
        self.assertEqual('a token', result)
 
2488
        self.assertEqual('a token', token)
2282
2489
 
2283
2490
    def test_lock_write_already_locked(self):
2284
2491
        transport_path = 'quack'
2375
2582
        the client is finished.
2376
2583
        """
2377
2584
        sink = repo._get_sink()
2378
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2585
        fmt = repository.format_registry.get_default()
2379
2586
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2380
2587
        self.assertEqual([], resume_tokens)
2381
2588
        self.assertEqual(set(), missing_keys)
2481
2688
                return True
2482
2689
        repo._real_repository = FakeRealRepository()
2483
2690
        sink = repo._get_sink()
2484
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2691
        fmt = repository.format_registry.get_default()
2485
2692
        stream = self.make_stream_with_inv_deltas(fmt)
2486
2693
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2487
2694
        # Every record from the first inventory delta should have been sent to
2622
2829
    """RemoteRepository.copy_content_into optimizations"""
2623
2830
 
2624
2831
    def test_copy_content_remote_to_local(self):
2625
 
        self.transport_server = server.SmartTCPServer_for_testing
 
2832
        self.transport_server = test_server.SmartTCPServer_for_testing
2626
2833
        src_repo = self.make_repository('repo1')
2627
2834
        src_repo = repository.Repository.open(self.get_url('repo1'))
2628
2835
        # At the moment the tarball-based copy_content_into can't write back
2707
2914
             ('pack collection autopack',)],
2708
2915
            client._calls)
2709
2916
 
 
2917
    def test_oom_error_reporting(self):
 
2918
        """An out-of-memory condition on the server is reported clearly"""
 
2919
        transport_path = 'quack'
 
2920
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2921
        client.add_expected_call(
 
2922
            'PackRepository.autopack', ('quack/',),
 
2923
            'error', ('MemoryError',))
 
2924
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
2925
        self.assertContainsRe(str(err), "^remote server out of mem")
 
2926
 
2710
2927
 
2711
2928
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2712
2929
    """Base class for unit tests for bzrlib.remote._translate_error."""
2785
3002
            detail='extra detail')
2786
3003
        self.assertEqual(expected_error, translated_error)
2787
3004
 
 
3005
    def test_norepository(self):
 
3006
        bzrdir = self.make_bzrdir('')
 
3007
        translated_error = self.translateTuple(('norepository',),
 
3008
            bzrdir=bzrdir)
 
3009
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3010
        self.assertEqual(expected_error, translated_error)
 
3011
 
2788
3012
    def test_LockContention(self):
2789
3013
        translated_error = self.translateTuple(('LockContention',))
2790
3014
        expected_error = errors.LockContention('(remote lock)')
2818
3042
        expected_error = errors.DivergedBranches(branch, other_branch)
2819
3043
        self.assertEqual(expected_error, translated_error)
2820
3044
 
 
3045
    def test_NotStacked(self):
 
3046
        branch = self.make_branch('')
 
3047
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3048
        expected_error = errors.NotStacked(branch)
 
3049
        self.assertEqual(expected_error, translated_error)
 
3050
 
2821
3051
    def test_ReadError_no_args(self):
2822
3052
        path = 'a path'
2823
3053
        translated_error = self.translateTuple(('ReadError',), path=path)
2839
3069
 
2840
3070
    def test_PermissionDenied_no_args(self):
2841
3071
        path = 'a path'
2842
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3072
        translated_error = self.translateTuple(('PermissionDenied',),
 
3073
            path=path)
2843
3074
        expected_error = errors.PermissionDenied(path)
2844
3075
        self.assertEqual(expected_error, translated_error)
2845
3076
 
2868
3099
        expected_error = errors.PermissionDenied(path, extra)
2869
3100
        self.assertEqual(expected_error, translated_error)
2870
3101
 
 
3102
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3103
 
 
3104
    def test_NoSuchFile_context_path(self):
 
3105
        local_path = "local path"
 
3106
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3107
            path=local_path)
 
3108
        expected_error = errors.ReadError(local_path)
 
3109
        self.assertEqual(expected_error, translated_error)
 
3110
 
 
3111
    def test_NoSuchFile_without_context(self):
 
3112
        remote_path = "remote path"
 
3113
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3114
        expected_error = errors.ReadError(remote_path)
 
3115
        self.assertEqual(expected_error, translated_error)
 
3116
 
 
3117
    def test_ReadOnlyError(self):
 
3118
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3119
        expected_error = errors.TransportNotPossible("readonly transport")
 
3120
        self.assertEqual(expected_error, translated_error)
 
3121
 
 
3122
    def test_MemoryError(self):
 
3123
        translated_error = self.translateTuple(('MemoryError',))
 
3124
        self.assertStartsWith(str(translated_error),
 
3125
            "remote server out of memory")
 
3126
 
 
3127
    def test_generic_IndexError_no_classname(self):
 
3128
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3129
        translated_error = self.translateErrorFromSmartServer(err)
 
3130
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3131
        self.assertEqual(expected_error, translated_error)
 
3132
 
 
3133
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3134
 
 
3135
    def test_generic_KeyError(self):
 
3136
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3137
        translated_error = self.translateErrorFromSmartServer(err)
 
3138
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3139
        self.assertEqual(expected_error, translated_error)
 
3140
 
2871
3141
 
2872
3142
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2873
3143
    """Unit tests for bzrlib.remote._translate_error's robustness.
2941
3211
        stacked_branch = self.make_branch('stacked', format='1.9')
2942
3212
        stacked_branch.set_stacked_on_url('../base')
2943
3213
        # start a server looking at this
2944
 
        smart_server = server.SmartTCPServer_for_testing()
 
3214
        smart_server = test_server.SmartTCPServer_for_testing()
2945
3215
        self.start_server(smart_server)
2946
3216
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2947
3217
        # can get its branch and repository
3018
3288
        _, stacked = branch_factory()
3019
3289
        source = stacked.repository._get_source(target_repository_format)
3020
3290
        tip = stacked.last_revision()
3021
 
        revs = stacked.repository.get_ancestry(tip)
3022
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3291
        stacked.repository._ensure_real()
 
3292
        graph = stacked.repository.get_graph()
 
3293
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3294
                if r != NULL_REVISION]
 
3295
        revs.reverse()
 
3296
        search = _mod_graph.PendingAncestryResult([tip], stacked.repository)
3023
3297
        self.reset_smart_call_log()
3024
3298
        stream = source.get_stream(search)
3025
 
        if None in revs:
3026
 
            revs.remove(None)
3027
3299
        # We trust that if a revision is in the stream the rest of the new
3028
3300
        # content for it is too, as per our main fetch tests; here we are
3029
3301
        # checking that the revisions are actually included at all, and their
3068
3340
        self.assertEqual(expected_revs, rev_ord)
3069
3341
        # Getting topological sort requires VFS calls still - one of which is
3070
3342
        # pushing up from the bound branch.
3071
 
        self.assertLength(13, self.hpss_calls)
 
3343
        self.assertLength(14, self.hpss_calls)
3072
3344
 
3073
3345
    def test_stacked_get_stream_groupcompress(self):
3074
3346
        # Repository._get_source.get_stream() from a stacked repository with
3103
3375
        super(TestRemoteBranchEffort, self).setUp()
3104
3376
        # Create a smart server that publishes whatever the backing VFS server
3105
3377
        # does.
3106
 
        self.smart_server = server.SmartTCPServer_for_testing()
 
3378
        self.smart_server = test_server.SmartTCPServer_for_testing()
3107
3379
        self.start_server(self.smart_server, self.get_server())
3108
3380
        # Log all HPSS calls into self.hpss_calls.
3109
3381
        _SmartClient.hooks.install_named_hook(
3115
3387
 
3116
3388
    def test_copy_content_into_avoids_revision_history(self):
3117
3389
        local = self.make_branch('local')
3118
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3119
 
        remote_backing_tree.commit("Commit.")
 
3390
        builder = self.make_branch_builder('remote')
 
3391
        builder.build_commit(message="Commit.")
3120
3392
        remote_branch_url = self.smart_server.get_url() + 'remote'
3121
3393
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3122
3394
        local.repository.fetch(remote_branch.repository)
3123
3395
        self.hpss_calls = []
3124
3396
        remote_branch.copy_content_into(local)
3125
3397
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
3398
 
 
3399
    def test_fetch_everything_needs_just_one_call(self):
 
3400
        local = self.make_branch('local')
 
3401
        builder = self.make_branch_builder('remote')
 
3402
        builder.build_commit(message="Commit.")
 
3403
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3404
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3405
        self.hpss_calls = []
 
3406
        local.repository.fetch(
 
3407
            remote_branch.repository,
 
3408
            fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
 
3409
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
3410
 
 
3411
    def override_verb(self, verb_name, verb):
 
3412
        request_handlers = request.request_handlers
 
3413
        orig_verb = request_handlers.get(verb_name)
 
3414
        request_handlers.register(verb_name, verb, override_existing=True)
 
3415
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
3416
                override_existing=True)
 
3417
 
 
3418
    def test_fetch_everything_backwards_compat(self):
 
3419
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
3420
        
 
3421
        Pre-2.4 do not support 'everything' searches with the
 
3422
        Repository.get_stream_1.19 verb.
 
3423
        """
 
3424
        verb_log = []
 
3425
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
3426
            """A version of the Repository.get_stream_1.19 verb patched to
 
3427
            reject 'everything' searches the way 2.3 and earlier do.
 
3428
            """
 
3429
            def recreate_search(self, repository, search_bytes,
 
3430
                                discard_excess=False):
 
3431
                verb_log.append(search_bytes.split('\n', 1)[0])
 
3432
                if search_bytes == 'everything':
 
3433
                    return (None,
 
3434
                            request.FailedSmartServerResponse(('BadSearch',)))
 
3435
                return super(OldGetStreamVerb,
 
3436
                        self).recreate_search(repository, search_bytes,
 
3437
                            discard_excess=discard_excess)
 
3438
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
3439
        local = self.make_branch('local')
 
3440
        builder = self.make_branch_builder('remote')
 
3441
        builder.build_commit(message="Commit.")
 
3442
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3443
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3444
        self.hpss_calls = []
 
3445
        local.repository.fetch(
 
3446
            remote_branch.repository,
 
3447
            fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
 
3448
        # make sure the overridden verb was used
 
3449
        self.assertLength(1, verb_log)
 
3450
        # more than one HPSS call is needed, but because it's a VFS callback
 
3451
        # its hard to predict exactly how many.
 
3452
        self.assertTrue(len(self.hpss_calls) > 1)
 
3453
 
 
3454
 
 
3455
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
3456
    tests.TestCaseWithTransport):
 
3457
    """Ensure correct handling of bound_location modifications.
 
3458
 
 
3459
    This is tested against a smart server as http://pad.lv/786980 was about a
 
3460
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
3461
    happen in this context.
 
3462
    """
 
3463
 
 
3464
    def setUp(self):
 
3465
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
3466
        self.transport_server = test_server.SmartTCPServer_for_testing
 
3467
 
 
3468
    def make_master_and_checkout(self, master_name, checkout_name):
 
3469
        # Create the master branch and its associated checkout
 
3470
        self.master = self.make_branch_and_tree(master_name)
 
3471
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
3472
        # Modify the master branch so there is something to update
 
3473
        self.master.commit('add stuff')
 
3474
        self.last_revid = self.master.commit('even more stuff')
 
3475
        self.bound_location = self.checkout.branch.get_bound_location()
 
3476
 
 
3477
    def assertUpdateSucceeds(self, new_location):
 
3478
        self.checkout.branch.set_bound_location(new_location)
 
3479
        self.checkout.update()
 
3480
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
3481
 
 
3482
    def test_without_final_slash(self):
 
3483
        self.make_master_and_checkout('master', 'checkout')
 
3484
        # For unclear reasons some users have a bound_location without a final
 
3485
        # '/', simulate that by forcing such a value
 
3486
        self.assertEndsWith(self.bound_location, '/')
 
3487
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
3488
 
 
3489
    def test_plus_sign(self):
 
3490
        self.make_master_and_checkout('+master', 'checkout')
 
3491
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
3492
 
 
3493
    def test_tilda(self):
 
3494
        # Embed ~ in the middle of the path just to avoid any $HOME
 
3495
        # interpretation
 
3496
        self.make_master_and_checkout('mas~ter', 'checkout')
 
3497
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))