/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

mergeĀ lp:~jelmer/bzr/commit-uses-config-stacks

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 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
25
25
 
26
26
import bz2
27
27
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
30
from bzrlib import (
30
31
    branch,
31
32
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    graph as _mod_graph,
35
37
    inventory,
36
38
    inventory_delta,
37
 
    pack,
38
39
    remote,
39
40
    repository,
40
41
    tests,
 
42
    transport,
41
43
    treebuilder,
42
 
    urlutils,
43
44
    versionedfile,
 
45
    vf_search,
44
46
    )
45
47
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
48
from bzrlib.bzrdir import (
 
49
    BzrDir,
 
50
    BzrDirFormat,
 
51
    RemoteBzrProber,
 
52
    )
 
53
from bzrlib.chk_serializer import chk_bencode_serializer
47
54
from bzrlib.remote import (
48
55
    RemoteBranch,
49
56
    RemoteBranchFormat,
52
59
    RemoteRepository,
53
60
    RemoteRepositoryFormat,
54
61
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import medium
 
62
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
 
63
from bzrlib.revision import (
 
64
    NULL_REVISION,
 
65
    Revision,
 
66
    )
 
67
from bzrlib.smart import medium, request
58
68
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
69
from bzrlib.smart.repository import (
 
70
    SmartServerRepositoryGetParentMap,
 
71
    SmartServerRepositoryGetStream_1_19,
 
72
    )
 
73
from bzrlib.symbol_versioning import deprecated_in
60
74
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
75
    test_server,
65
76
    )
66
 
from bzrlib.transport import get_transport
 
77
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
78
from bzrlib.transport.memory import MemoryTransport
68
79
from bzrlib.transport.remote import (
69
80
    RemoteTransport,
70
81
    RemoteSSHTransport,
71
82
    RemoteTCPTransport,
72
 
)
73
 
 
74
 
def load_tests(standard_tests, module, loader):
75
 
    to_adapt, result = split_suite_by_condition(
76
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
 
    smart_server_version_scenarios = [
 
83
    )
 
84
 
 
85
 
 
86
load_tests = load_tests_apply_scenarios
 
87
 
 
88
 
 
89
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
90
 
 
91
    scenarios = [
78
92
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
93
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
94
        ('HPSS-v3',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
82
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
83
 
 
84
 
 
85
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
95
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
96
 
86
97
 
87
98
    def setUp(self):
88
99
        super(BasicRemoteObjectTests, self).setUp()
89
100
        self.transport = self.get_transport()
90
101
        # make a branch that can be opened over the smart transport
91
102
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
103
        self.addCleanup(self.transport.disconnect)
96
104
 
97
105
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
106
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
107
        self.assertIsInstance(b, BzrDir)
100
108
 
101
109
    def test_open_remote_branch(self):
102
110
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
111
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
112
        branch = b.open_branch()
105
113
        self.assertIsInstance(branch, Branch)
106
114
 
114
122
 
115
123
    def test_remote_branch_revision_history(self):
116
124
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
 
125
        self.assertEqual([],
 
126
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
127
        r1 = self.local_wt.commit('1st commit')
119
128
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
 
129
        self.assertEqual([r1, r2],
 
130
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
121
131
 
122
132
    def test_find_correct_format(self):
123
133
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
134
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
135
        self.assertTrue(bzrdir.RemoteBzrProber
 
136
                        in controldir.ControlDirFormat._server_probers)
 
137
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
138
 
129
139
    def test_open_detected_smart_format(self):
130
140
        fmt = BzrDirFormat.find_format(self.transport)
359
369
        a given client_base and transport_base.
360
370
        """
361
371
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
372
        t = transport.get_transport(transport_base)
 
373
        result = client_medium.remote_path_from_transport(t)
364
374
        self.assertEqual(expected, result)
365
375
 
366
376
    def test_remote_path_from_transport(self):
377
387
        a given transport_base and relpath of that transport.  (Note that
378
388
        HttpTransportBase is a subclass of SmartClientMedium)
379
389
        """
380
 
        base_transport = get_transport(transport_base)
 
390
        base_transport = transport.get_transport(transport_base)
381
391
        client_medium = base_transport.get_smart_medium()
382
392
        cloned_transport = base_transport.clone(relpath)
383
393
        result = client_medium.remote_path_from_transport(cloned_transport)
450
460
        client.add_expected_call(
451
461
            'BzrDir.open_branchV3', ('quack/',),
452
462
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
463
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
464
            _client=client)
455
465
        result = a_bzrdir.cloning_metadir()
456
466
        # We should have got a control dir matching the referenced branch.
469
479
        client.add_expected_call(
470
480
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
481
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
482
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
483
            _client=client)
474
484
        result = a_bzrdir.cloning_metadir()
475
485
        # We should have got a reference control dir with default branch and
480
490
        self.assertEqual(None, result._branch_format)
481
491
        self.assertFinished(client)
482
492
 
 
493
    def test_unknown(self):
 
494
        transport = self.get_transport('quack')
 
495
        referenced = self.make_branch('referenced')
 
496
        expected = referenced.bzrdir.cloning_metadir()
 
497
        client = FakeClient(transport.base)
 
498
        client.add_expected_call(
 
499
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
500
            'success', ('unknown', 'unknown', ('branch', ''))),
 
501
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
502
            _client=client)
 
503
        self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
 
504
 
 
505
 
 
506
class TestBzrDirDestroyBranch(TestRemote):
 
507
 
 
508
    def test_destroy_default(self):
 
509
        transport = self.get_transport('quack')
 
510
        referenced = self.make_branch('referenced')
 
511
        client = FakeClient(transport.base)
 
512
        client.add_expected_call(
 
513
            'BzrDir.destroy_branch', ('quack/', ),
 
514
            'success', ('ok',)),
 
515
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
516
            _client=client)
 
517
        a_bzrdir.destroy_branch()
 
518
        self.assertFinished(client)
 
519
 
 
520
    def test_destroy_named(self):
 
521
        transport = self.get_transport('quack')
 
522
        referenced = self.make_branch('referenced')
 
523
        client = FakeClient(transport.base)
 
524
        client.add_expected_call(
 
525
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
526
            'success', ('ok',)),
 
527
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
528
            _client=client)
 
529
        a_bzrdir.destroy_branch("foo")
 
530
        self.assertFinished(client)
 
531
 
 
532
 
 
533
class TestBzrDirHasWorkingTree(TestRemote):
 
534
 
 
535
    def test_has_workingtree(self):
 
536
        transport = self.get_transport('quack')
 
537
        client = FakeClient(transport.base)
 
538
        client.add_expected_call(
 
539
            'BzrDir.has_workingtree', ('quack/',),
 
540
            'success', ('yes',)),
 
541
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
542
            _client=client)
 
543
        self.assertTrue(a_bzrdir.has_workingtree())
 
544
        self.assertFinished(client)
 
545
 
 
546
    def test_no_workingtree(self):
 
547
        transport = self.get_transport('quack')
 
548
        client = FakeClient(transport.base)
 
549
        client.add_expected_call(
 
550
            'BzrDir.has_workingtree', ('quack/',),
 
551
            'success', ('no',)),
 
552
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
553
            _client=client)
 
554
        self.assertFalse(a_bzrdir.has_workingtree())
 
555
        self.assertFinished(client)
 
556
 
 
557
 
 
558
class TestBzrDirDestroyRepository(TestRemote):
 
559
 
 
560
    def test_destroy_repository(self):
 
561
        transport = self.get_transport('quack')
 
562
        client = FakeClient(transport.base)
 
563
        client.add_expected_call(
 
564
            'BzrDir.destroy_repository', ('quack/',),
 
565
            'success', ('ok',)),
 
566
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
567
            _client=client)
 
568
        a_bzrdir.destroy_repository()
 
569
        self.assertFinished(client)
 
570
 
483
571
 
484
572
class TestBzrDirOpen(TestRemote):
485
573
 
495
583
        client.add_expected_call(
496
584
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
585
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
586
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
587
        self.assertFinished(client)
500
588
 
501
589
    def test_present_without_workingtree(self):
502
590
        client, transport = self.make_fake_client_and_transport()
503
591
        client.add_expected_call(
504
592
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
593
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
594
            _client=client, _force_probe=True)
507
595
        self.assertIsInstance(bd, RemoteBzrDir)
508
596
        self.assertFalse(bd.has_workingtree())
513
601
        client, transport = self.make_fake_client_and_transport()
514
602
        client.add_expected_call(
515
603
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
604
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
605
            _client=client, _force_probe=True)
518
606
        self.assertIsInstance(bd, RemoteBzrDir)
519
607
        self.assertTrue(bd.has_workingtree())
526
614
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
615
        client.add_expected_call(
528
616
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
617
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
618
            _client=client, _force_probe=True)
531
619
        self.assertIsInstance(bd, RemoteBzrDir)
532
620
        self.assertFinished(client)
548
636
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
637
        client.add_expected_call(
550
638
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
639
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
640
            _client=client, _force_probe=True)
553
641
        self.assertIsInstance(bd, RemoteBzrDir)
554
642
        self.assertFinished(client)
585
673
        client.add_expected_call(
586
674
            'Branch.get_stacked_on_url', ('quack/',),
587
675
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
676
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
677
            _client=client)
590
678
        result = bzrdir.open_branch()
591
679
        self.assertIsInstance(result, RemoteBranch)
598
686
        transport = transport.clone('quack')
599
687
        client = FakeClient(transport.base)
600
688
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
689
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
690
            _client=client)
603
691
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
692
        self.assertEqual(
609
697
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
698
        # branch opening, not any other network requests.
611
699
        calls = []
612
 
        def open_branch():
 
700
        def open_branch(name=None, possible_transports=None):
613
701
            calls.append("Called")
614
702
            return "a-branch"
615
703
        transport = MemoryTransport()
616
704
        # no requests on the network - catches other api calls being made.
617
705
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
706
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
707
            _client=client)
620
708
        # patch the open_branch call to record that it was called.
621
709
        bzrdir.open_branch = open_branch
640
728
        client.add_expected_call(
641
729
            'Branch.get_stacked_on_url', ('~hello/',),
642
730
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
731
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
732
            _client=client)
645
733
        result = bzrdir.open_branch()
646
734
        self.assertFinished(client)
663
751
        client.add_success_response(
664
752
            'ok', '', rich_response, subtree_response, external_lookup,
665
753
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
754
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
755
            _client=client)
668
756
        result = bzrdir.open_repository()
669
757
        self.assertEqual(
686
774
        old.
687
775
        """
688
776
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
777
            RemoteBzrProber.probe_transport, OldServerTransport())
690
778
 
691
779
 
692
780
class TestBzrDirCreateBranch(TestRemote):
715
803
            'BzrDir.create_branch', ('quack/', network_name),
716
804
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
805
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
806
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
807
            _client=client)
720
808
        branch = a_bzrdir.create_branch()
721
809
        # We should have got a remote branch
724
812
        format = branch._format
725
813
        self.assertEqual(network_name, format.network_name())
726
814
 
 
815
    def test_already_open_repo_and_reused_medium(self):
 
816
        """Bug 726584: create_branch(..., repository=repo) should work
 
817
        regardless of what the smart medium's base URL is.
 
818
        """
 
819
        self.transport_server = test_server.SmartTCPServer_for_testing
 
820
        transport = self.get_transport('.')
 
821
        repo = self.make_repository('quack')
 
822
        # Client's medium rooted a transport root (not at the bzrdir)
 
823
        client = FakeClient(transport.base)
 
824
        transport = transport.clone('quack')
 
825
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
826
        reference_format = reference_bzrdir_format.get_branch_format()
 
827
        network_name = reference_format.network_name()
 
828
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
829
        reference_repo_name = reference_repo_fmt.network_name()
 
830
        client.add_expected_call(
 
831
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
832
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
833
            reference_repo_name))
 
834
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
835
            _client=client)
 
836
        branch = a_bzrdir.create_branch(repository=repo)
 
837
        # We should have got a remote branch
 
838
        self.assertIsInstance(branch, remote.RemoteBranch)
 
839
        # its format should have the settings from the response
 
840
        format = branch._format
 
841
        self.assertEqual(network_name, format.network_name())
 
842
 
727
843
 
728
844
class TestBzrDirCreateRepository(TestRemote):
729
845
 
750
866
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
867
                'False'),
752
868
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
869
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
870
            _client=client)
755
871
        repo = a_bzrdir.create_repository()
756
872
        # We should have got a remote repository
785
901
        client.add_success_response('stat', '0', '65535')
786
902
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
903
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
904
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
905
            _client=client)
790
906
        repo = bzrdir.open_repository()
791
907
        self.assertEqual(
818
934
        client.add_success_response('stat', '0', '65535')
819
935
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
936
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
937
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
938
            _client=client)
823
939
        repo = bzrdir.open_repository()
824
940
        self.assertEqual(
839
955
        transport = transport.clone('quack')
840
956
        client = FakeClient(transport.base)
841
957
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
958
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
959
            _client=client)
844
960
        repo = bzrdir.open_repository()
845
961
        self.assertEqual(
852
968
 
853
969
    def test_success(self):
854
970
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
971
        fmt = RemoteBzrDirFormat()
856
972
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
973
        transport = self.get_transport()
858
974
        client = FakeClient(transport.base)
874
990
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
991
        corresponding error from the client.
876
992
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
993
        fmt = RemoteBzrDirFormat()
878
994
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
995
        transport = self.get_transport()
880
996
        client = FakeClient(transport.base)
898
1014
        """Integration test for error translation."""
899
1015
        transport = self.make_smart_server('foo')
900
1016
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1017
        fmt = RemoteBzrDirFormat()
902
1018
        err = self.assertRaises(errors.NoSuchFile,
903
1019
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1020
 
935
1051
 
936
1052
    def make_remote_bzrdir(self, transport, client):
937
1053
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1054
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1055
            _client=client)
940
1056
 
941
1057
 
967
1083
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1084
 
969
1085
 
 
1086
class TestBranchBreakLock(RemoteBranchTestCase):
 
1087
 
 
1088
    def test_break_lock(self):
 
1089
        transport_path = 'quack'
 
1090
        transport = MemoryTransport()
 
1091
        client = FakeClient(transport.base)
 
1092
        client.add_expected_call(
 
1093
            'Branch.get_stacked_on_url', ('quack/',),
 
1094
            'error', ('NotStacked',))
 
1095
        client.add_expected_call(
 
1096
            'Branch.break_lock', ('quack/',),
 
1097
            'success', ('ok',))
 
1098
        transport.mkdir('quack')
 
1099
        transport = transport.clone('quack')
 
1100
        branch = self.make_remote_branch(transport, client)
 
1101
        branch.break_lock()
 
1102
        self.assertFinished(client)
 
1103
 
 
1104
 
 
1105
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1106
 
 
1107
    def test_get_physical_lock_status_yes(self):
 
1108
        transport = MemoryTransport()
 
1109
        client = FakeClient(transport.base)
 
1110
        client.add_expected_call(
 
1111
            'Branch.get_stacked_on_url', ('quack/',),
 
1112
            'error', ('NotStacked',))
 
1113
        client.add_expected_call(
 
1114
            'Branch.get_physical_lock_status', ('quack/',),
 
1115
            'success', ('yes',))
 
1116
        transport.mkdir('quack')
 
1117
        transport = transport.clone('quack')
 
1118
        branch = self.make_remote_branch(transport, client)
 
1119
        result = branch.get_physical_lock_status()
 
1120
        self.assertFinished(client)
 
1121
        self.assertEqual(True, result)
 
1122
 
 
1123
    def test_get_physical_lock_status_no(self):
 
1124
        transport = MemoryTransport()
 
1125
        client = FakeClient(transport.base)
 
1126
        client.add_expected_call(
 
1127
            'Branch.get_stacked_on_url', ('quack/',),
 
1128
            'error', ('NotStacked',))
 
1129
        client.add_expected_call(
 
1130
            'Branch.get_physical_lock_status', ('quack/',),
 
1131
            'success', ('no',))
 
1132
        transport.mkdir('quack')
 
1133
        transport = transport.clone('quack')
 
1134
        branch = self.make_remote_branch(transport, client)
 
1135
        result = branch.get_physical_lock_status()
 
1136
        self.assertFinished(client)
 
1137
        self.assertEqual(False, result)
 
1138
 
 
1139
 
970
1140
class TestBranchGetParent(RemoteBranchTestCase):
971
1141
 
972
1142
    def test_no_parent(self):
1143
1313
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1314
 
1145
1315
 
 
1316
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1317
 
 
1318
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1319
        transport = MemoryTransport()
 
1320
        client = FakeClient(transport.base)
 
1321
        client.add_expected_call(
 
1322
            'Branch.get_stacked_on_url', ('quack/',),
 
1323
            'error', ('NotStacked',))
 
1324
        client.add_expected_call(
 
1325
            'Branch.last_revision_info', ('quack/',),
 
1326
            'success', ('ok', '1', 'rev-tip'))
 
1327
        client.add_expected_call(
 
1328
            'Branch.get_config_file', ('quack/',),
 
1329
            'success', ('ok',), '')
 
1330
        transport.mkdir('quack')
 
1331
        transport = transport.clone('quack')
 
1332
        branch = self.make_remote_branch(transport, client)
 
1333
        result = branch.heads_to_fetch()
 
1334
        self.assertFinished(client)
 
1335
        self.assertEqual((set(['rev-tip']), set()), result)
 
1336
 
 
1337
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1338
        transport = MemoryTransport()
 
1339
        client = FakeClient(transport.base)
 
1340
        client.add_expected_call(
 
1341
            'Branch.get_stacked_on_url', ('quack/',),
 
1342
            'error', ('NotStacked',))
 
1343
        client.add_expected_call(
 
1344
            'Branch.last_revision_info', ('quack/',),
 
1345
            'success', ('ok', '1', 'rev-tip'))
 
1346
        client.add_expected_call(
 
1347
            'Branch.get_config_file', ('quack/',),
 
1348
            'success', ('ok',), 'branch.fetch_tags = True')
 
1349
        # XXX: this will break if the default format's serialization of tags
 
1350
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1351
        client.add_expected_call(
 
1352
            'Branch.get_tags_bytes', ('quack/',),
 
1353
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1354
        transport.mkdir('quack')
 
1355
        transport = transport.clone('quack')
 
1356
        branch = self.make_remote_branch(transport, client)
 
1357
        result = branch.heads_to_fetch()
 
1358
        self.assertFinished(client)
 
1359
        self.assertEqual(
 
1360
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1361
 
 
1362
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1363
        transport = MemoryTransport()
 
1364
        client = FakeClient(transport.base)
 
1365
        client.add_expected_call(
 
1366
            'Branch.get_stacked_on_url', ('quack/',),
 
1367
            'error', ('NotStacked',))
 
1368
        client.add_expected_call(
 
1369
            'Branch.heads_to_fetch', ('quack/',),
 
1370
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1371
        transport.mkdir('quack')
 
1372
        transport = transport.clone('quack')
 
1373
        branch = self.make_remote_branch(transport, client)
 
1374
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1375
        result = branch.heads_to_fetch()
 
1376
        self.assertFinished(client)
 
1377
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1378
 
 
1379
    def make_branch_with_tags(self):
 
1380
        self.setup_smart_server_with_call_log()
 
1381
        # Make a branch with a single revision.
 
1382
        builder = self.make_branch_builder('foo')
 
1383
        builder.start_series()
 
1384
        builder.build_snapshot('tip', None, [
 
1385
            ('add', ('', 'root-id', 'directory', ''))])
 
1386
        builder.finish_series()
 
1387
        branch = builder.get_branch()
 
1388
        # Add two tags to that branch
 
1389
        branch.tags.set_tag('tag-1', 'rev-1')
 
1390
        branch.tags.set_tag('tag-2', 'rev-2')
 
1391
        return branch
 
1392
 
 
1393
    def test_backwards_compatible(self):
 
1394
        branch = self.make_branch_with_tags()
 
1395
        c = branch.get_config()
 
1396
        c.set_user_option('branch.fetch_tags', 'True')
 
1397
        self.addCleanup(branch.lock_read().unlock)
 
1398
        # Disable the heads_to_fetch verb
 
1399
        verb = 'Branch.heads_to_fetch'
 
1400
        self.disable_verb(verb)
 
1401
        self.reset_smart_call_log()
 
1402
        result = branch.heads_to_fetch()
 
1403
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1404
        self.assertEqual(
 
1405
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1406
             'Branch.get_tags_bytes'],
 
1407
            [call.call.method for call in self.hpss_calls])
 
1408
 
 
1409
    def test_backwards_compatible_no_tags(self):
 
1410
        branch = self.make_branch_with_tags()
 
1411
        c = branch.get_config()
 
1412
        c.set_user_option('branch.fetch_tags', 'False')
 
1413
        self.addCleanup(branch.lock_read().unlock)
 
1414
        # Disable the heads_to_fetch verb
 
1415
        verb = 'Branch.heads_to_fetch'
 
1416
        self.disable_verb(verb)
 
1417
        self.reset_smart_call_log()
 
1418
        result = branch.heads_to_fetch()
 
1419
        self.assertEqual((set(['tip']), set()), result)
 
1420
        self.assertEqual(
 
1421
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1422
            [call.call.method for call in self.hpss_calls])
 
1423
 
 
1424
 
1146
1425
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1426
 
1148
1427
    def test_empty_branch(self):
1203
1482
        client.add_expected_call(
1204
1483
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1484
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1485
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1486
            _client=client)
1208
1487
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1488
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1515
        # this will also do vfs access, but that goes direct to the transport
1237
1516
        # and isn't seen by the FakeClient.
1238
1517
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1518
            RemoteBzrDirFormat(), _client=client)
1240
1519
        branch = bzrdir.open_branch()
1241
1520
        result = branch.get_stacked_on_url()
1242
1521
        self.assertEqual('../base', result)
1269
1548
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1549
            'success', ('ok', '../base'))
1271
1550
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1551
            RemoteBzrDirFormat(), _client=client)
1273
1552
        branch = bzrdir.open_branch()
1274
1553
        result = branch.get_stacked_on_url()
1275
1554
        self.assertEqual('../base', result)
1283
1562
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1563
 
1285
1564
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1565
        # _set_last_revision_info('null:') is translated to calling
1287
1566
        # Branch.set_last_revision(path, '') on the wire.
1288
1567
        transport = MemoryTransport()
1289
1568
        transport.mkdir('branch')
1307
1586
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1587
            'success', ('ok',))
1309
1588
        branch = self.make_remote_branch(transport, client)
1310
 
        # This is a hack to work around the problem that RemoteBranch currently
1311
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1312
 
        branch._ensure_real = lambda: None
1313
1589
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1590
        result = branch._set_last_revision(NULL_REVISION)
1315
1591
        branch.unlock()
1316
1592
        self.assertEqual(None, result)
1317
1593
        self.assertFinished(client)
1318
1594
 
1319
1595
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1596
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1597
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1598
        transport = MemoryTransport()
1323
1599
        transport.mkdir('branch')
1344
1620
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1621
            'success', ('ok',))
1346
1622
        branch = self.make_remote_branch(transport, client)
1347
 
        # This is a hack to work around the problem that RemoteBranch currently
1348
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1349
 
        branch._ensure_real = lambda: None
1350
1623
        # Lock the branch, reset the record of remote calls.
1351
1624
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1625
        result = branch._set_last_revision('rev-id2')
1353
1626
        branch.unlock()
1354
1627
        self.assertEqual(None, result)
1355
1628
        self.assertFinished(client)
1385
1658
        branch = self.make_remote_branch(transport, client)
1386
1659
        branch.lock_write()
1387
1660
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1661
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1662
        branch.unlock()
1390
1663
        self.assertFinished(client)
1391
1664
 
1419
1692
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1693
            'success', ('ok',))
1421
1694
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1695
        branch.lock_write()
1424
1696
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1697
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1698
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1699
            errors.TipChangeRejected,
 
1700
            branch._set_last_revision, 'rev-id')
1428
1701
        # The UTF-8 message from the response has been decoded into a unicode
1429
1702
        # object.
1430
1703
        self.assertIsInstance(err.msg, unicode)
1618
1891
    def test_get_multi_line_branch_conf(self):
1619
1892
        # Make sure that multiple-line branch.conf files are supported
1620
1893
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1894
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1895
        client = FakeClient()
1623
1896
        client.add_expected_call(
1624
1897
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1925
        branch.unlock()
1653
1926
        self.assertFinished(client)
1654
1927
 
 
1928
    def test_set_option_with_dict(self):
 
1929
        client = FakeClient()
 
1930
        client.add_expected_call(
 
1931
            'Branch.get_stacked_on_url', ('memory:///',),
 
1932
            'error', ('NotStacked',),)
 
1933
        client.add_expected_call(
 
1934
            'Branch.lock_write', ('memory:///', '', ''),
 
1935
            'success', ('ok', 'branch token', 'repo token'))
 
1936
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1937
        client.add_expected_call(
 
1938
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1939
            'repo token', encoded_dict_value, 'foo', ''),
 
1940
            'success', ())
 
1941
        client.add_expected_call(
 
1942
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1943
            'success', ('ok',))
 
1944
        transport = MemoryTransport()
 
1945
        branch = self.make_remote_branch(transport, client)
 
1946
        branch.lock_write()
 
1947
        config = branch._get_config()
 
1948
        config.set_option(
 
1949
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1950
            'foo')
 
1951
        branch.unlock()
 
1952
        self.assertFinished(client)
 
1953
 
1655
1954
    def test_backwards_compat_set_option(self):
1656
1955
        self.setup_smart_server_with_call_log()
1657
1956
        branch = self.make_branch('.')
1664
1963
        self.assertLength(10, self.hpss_calls)
1665
1964
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
1965
 
 
1966
    def test_backwards_compat_set_option_with_dict(self):
 
1967
        self.setup_smart_server_with_call_log()
 
1968
        branch = self.make_branch('.')
 
1969
        verb = 'Branch.set_config_option_dict'
 
1970
        self.disable_verb(verb)
 
1971
        branch.lock_write()
 
1972
        self.addCleanup(branch.unlock)
 
1973
        self.reset_smart_call_log()
 
1974
        config = branch._get_config()
 
1975
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
1976
        config.set_option(value_dict, 'name')
 
1977
        self.assertLength(10, self.hpss_calls)
 
1978
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
1979
 
 
1980
 
 
1981
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
1982
 
 
1983
    def test_get_branch_conf(self):
 
1984
        # in an empty branch we decode the response properly
 
1985
        client = FakeClient()
 
1986
        client.add_expected_call(
 
1987
            'Branch.get_stacked_on_url', ('memory:///',),
 
1988
            'error', ('NotStacked',),)
 
1989
        client.add_success_response_with_body('# config file body', 'ok')
 
1990
        transport = MemoryTransport()
 
1991
        branch = self.make_remote_branch(transport, client)
 
1992
        config = branch.get_config_stack()
 
1993
        config.get("email")
 
1994
        config.get("log_format")
 
1995
        self.assertEqual(
 
1996
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
1997
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
1998
            client._calls)
 
1999
 
 
2000
    def test_set_branch_conf(self):
 
2001
        client = FakeClient()
 
2002
        client.add_expected_call(
 
2003
            'Branch.get_stacked_on_url', ('memory:///',),
 
2004
            'error', ('NotStacked',),)
 
2005
        client.add_expected_call(
 
2006
            'Branch.lock_write', ('memory:///', '', ''),
 
2007
            'success', ('ok', 'branch token', 'repo token'))
 
2008
        client.add_expected_call(
 
2009
            'Branch.get_config_file', ('memory:///', ),
 
2010
            'success', ('ok', ), "# line 1\n")
 
2011
        client.add_expected_call(
 
2012
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2013
            'repo token'),
 
2014
            'success', ('ok',))
 
2015
        client.add_expected_call(
 
2016
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2017
            'success', ('ok',))
 
2018
        transport = MemoryTransport()
 
2019
        branch = self.make_remote_branch(transport, client)
 
2020
        branch.lock_write()
 
2021
        config = branch.get_config_stack()
 
2022
        config.set('email', 'The Dude <lebowski@example.com>')
 
2023
        branch.unlock()
 
2024
        self.assertFinished(client)
 
2025
        self.assertEqual(
 
2026
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2027
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2028
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2029
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2030
                 ('memory:///', 'branch token', 'repo token'),
 
2031
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2032
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2033
            client._calls)
 
2034
 
1667
2035
 
1668
2036
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2037
 
1683
2051
        self.assertFinished(client)
1684
2052
 
1685
2053
 
 
2054
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2055
 
 
2056
    def test_simple(self):
 
2057
        transport = MemoryTransport()
 
2058
        client = FakeClient(transport.base)
 
2059
        client.add_expected_call(
 
2060
            'Branch.get_stacked_on_url', ('quack/',),
 
2061
            'error', ('NotStacked',),)
 
2062
        client.add_expected_call(
 
2063
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2064
            'success', ('ok', '0',),)
 
2065
        client.add_expected_call(
 
2066
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2067
            'error', ('NoSuchRevision', 'unknown',),)
 
2068
        transport.mkdir('quack')
 
2069
        transport = transport.clone('quack')
 
2070
        branch = self.make_remote_branch(transport, client)
 
2071
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2072
        self.assertRaises(errors.NoSuchRevision,
 
2073
            branch.revision_id_to_revno, 'unknown')
 
2074
        self.assertFinished(client)
 
2075
 
 
2076
    def test_dotted(self):
 
2077
        transport = MemoryTransport()
 
2078
        client = FakeClient(transport.base)
 
2079
        client.add_expected_call(
 
2080
            'Branch.get_stacked_on_url', ('quack/',),
 
2081
            'error', ('NotStacked',),)
 
2082
        client.add_expected_call(
 
2083
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2084
            'success', ('ok', '0',),)
 
2085
        client.add_expected_call(
 
2086
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2087
            'error', ('NoSuchRevision', 'unknown',),)
 
2088
        transport.mkdir('quack')
 
2089
        transport = transport.clone('quack')
 
2090
        branch = self.make_remote_branch(transport, client)
 
2091
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2092
        self.assertRaises(errors.NoSuchRevision,
 
2093
            branch.revision_id_to_dotted_revno, 'unknown')
 
2094
        self.assertFinished(client)
 
2095
 
 
2096
    def test_dotted_no_smart_verb(self):
 
2097
        self.setup_smart_server_with_call_log()
 
2098
        branch = self.make_branch('.')
 
2099
        self.disable_verb('Branch.revision_id_to_revno')
 
2100
        self.reset_smart_call_log()
 
2101
        self.assertEquals((0, ),
 
2102
            branch.revision_id_to_dotted_revno('null:'))
 
2103
        self.assertLength(7, self.hpss_calls)
 
2104
 
 
2105
 
1686
2106
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2107
 
1688
2108
    def test__get_config(self):
1805
2225
        client = FakeClient(transport.base)
1806
2226
        transport = transport.clone(transport_path)
1807
2227
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2228
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2229
            _client=False)
1810
2230
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2231
        return repo, client
1819
2239
 
1820
2240
    def test_get_format_description(self):
1821
2241
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2242
        real_format = branch.format_registry.get_default()
1823
2243
        remote_format._network_name = real_format.network_name()
1824
2244
        self.assertEqual(remoted_description(real_format),
1825
2245
            remote_format.get_format_description())
1828
2248
class TestRepositoryFormat(TestRemoteRepository):
1829
2249
 
1830
2250
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2251
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2252
        true_format = RemoteRepositoryFormat()
1833
2253
        true_format._network_name = true_name
1834
2254
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2255
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2256
        false_format = RemoteRepositoryFormat()
1837
2257
        false_format._network_name = false_name
1838
2258
        self.assertEqual(False, false_format.fast_deltas)
1839
2259
 
1840
2260
    def test_get_format_description(self):
1841
2261
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2262
        real_format = repository.format_registry.get_default()
1843
2263
        remote_repo_format._network_name = real_format.network_name()
1844
2264
        self.assertEqual(remoted_description(real_format),
1845
2265
            remote_repo_format.get_format_description())
1846
2266
 
1847
2267
 
 
2268
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2269
 
 
2270
    def test_empty(self):
 
2271
        transport_path = 'quack'
 
2272
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2273
        client.add_success_response_with_body('', 'ok')
 
2274
        self.assertEquals([], repo.all_revision_ids())
 
2275
        self.assertEqual(
 
2276
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2277
             ('quack/',))],
 
2278
            client._calls)
 
2279
 
 
2280
    def test_with_some_content(self):
 
2281
        transport_path = 'quack'
 
2282
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2283
        client.add_success_response_with_body(
 
2284
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2285
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2286
            repo.all_revision_ids())
 
2287
        self.assertEqual(
 
2288
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2289
             ('quack/',))],
 
2290
            client._calls)
 
2291
 
 
2292
 
1848
2293
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2294
 
1850
2295
    def test_revid_none(self):
1903
2348
                         result)
1904
2349
 
1905
2350
 
 
2351
class TestRepositoryBreakLock(TestRemoteRepository):
 
2352
 
 
2353
    def test_break_lock(self):
 
2354
        transport_path = 'quack'
 
2355
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2356
        client.add_success_response('ok')
 
2357
        repo.break_lock()
 
2358
        self.assertEqual(
 
2359
            [('call', 'Repository.break_lock', ('quack/',))],
 
2360
            client._calls)
 
2361
 
 
2362
 
 
2363
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2364
 
 
2365
    def test_get_serializer_format(self):
 
2366
        transport_path = 'hill'
 
2367
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2368
        client.add_success_response('ok', '7')
 
2369
        self.assertEquals('7', repo.get_serializer_format())
 
2370
        self.assertEqual(
 
2371
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2372
              ('hill/', ))],
 
2373
            client._calls)
 
2374
 
 
2375
 
 
2376
class TestRepositoryReconcile(TestRemoteRepository):
 
2377
 
 
2378
    def test_reconcile(self):
 
2379
        transport_path = 'hill'
 
2380
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2381
        body = ("garbage_inventories: 2\n"
 
2382
                "inconsistent_parents: 3\n")
 
2383
        client.add_expected_call(
 
2384
            'Repository.lock_write', ('hill/', ''),
 
2385
            'success', ('ok', 'a token'))
 
2386
        client.add_success_response_with_body(body, 'ok')
 
2387
        reconciler = repo.reconcile()
 
2388
        self.assertEqual(
 
2389
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2390
             ('call_expecting_body', 'Repository.reconcile',
 
2391
                ('hill/', 'a token'))],
 
2392
            client._calls)
 
2393
        self.assertEquals(2, reconciler.garbage_inventories)
 
2394
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2395
 
 
2396
 
 
2397
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2398
 
 
2399
    def test_text(self):
 
2400
        # ('ok',), body with signature text
 
2401
        transport_path = 'quack'
 
2402
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2403
        client.add_success_response_with_body(
 
2404
            'THETEXT', 'ok')
 
2405
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2406
        self.assertEqual(
 
2407
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2408
             ('quack/', 'revid'))],
 
2409
            client._calls)
 
2410
 
 
2411
    def test_no_signature(self):
 
2412
        transport_path = 'quick'
 
2413
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2414
        client.add_error_response('nosuchrevision', 'unknown')
 
2415
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2416
                "unknown")
 
2417
        self.assertEqual(
 
2418
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2419
              ('quick/', 'unknown'))],
 
2420
            client._calls)
 
2421
 
 
2422
 
1906
2423
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2424
 
1908
2425
    def test_get_graph(self):
1913
2430
        self.assertNotEqual(graph._parents_provider, repo)
1914
2431
 
1915
2432
 
 
2433
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2434
 
 
2435
    def test_add_signature_text(self):
 
2436
        transport_path = 'quack'
 
2437
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2438
        client.add_expected_call(
 
2439
            'Repository.lock_write', ('quack/', ''),
 
2440
            'success', ('ok', 'a token'))
 
2441
        client.add_expected_call(
 
2442
            'Repository.start_write_group', ('quack/', 'a token'),
 
2443
            'success', ('ok', ('token1', )))
 
2444
        client.add_expected_call(
 
2445
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2446
                'token1'),
 
2447
            'success', ('ok', ), None)
 
2448
        repo.lock_write()
 
2449
        repo.start_write_group()
 
2450
        self.assertIs(None,
 
2451
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2452
        self.assertEqual(
 
2453
            ('call_with_body_bytes_expecting_body',
 
2454
              'Repository.add_signature_text',
 
2455
                ('quack/', 'a token', 'rev1', 'token1'),
 
2456
              'every bloody emperor'),
 
2457
            client._calls[-1])
 
2458
 
 
2459
 
1916
2460
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2461
 
1918
2462
    def test_get_parent_map_caching(self):
1968
2512
        parents = repo.get_parent_map([rev_id])
1969
2513
        self.assertEqual(
1970
2514
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2515
              'Repository.get_parent_map',
 
2516
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2517
             ('disconnect medium',),
1974
2518
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2519
              ('quack/', ''))],
2095
2639
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2640
        self.assertLength(0, self.hpss_calls)
2097
2641
 
 
2642
    def test_exposes_get_cached_parent_map(self):
 
2643
        """RemoteRepository exposes get_cached_parent_map from
 
2644
        _unstacked_provider
 
2645
        """
 
2646
        r1 = u'\u0e33'.encode('utf8')
 
2647
        r2 = u'\u0dab'.encode('utf8')
 
2648
        lines = [' '.join([r2, r1]), r1]
 
2649
        encoded_body = bz2.compress('\n'.join(lines))
 
2650
 
 
2651
        transport_path = 'quack'
 
2652
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2653
        client.add_success_response_with_body(encoded_body, 'ok')
 
2654
        repo.lock_read()
 
2655
        # get_cached_parent_map should *not* trigger an RPC
 
2656
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2657
        self.assertEqual([], client._calls)
 
2658
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2659
        self.assertEqual({r1: (NULL_REVISION,)},
 
2660
            repo.get_cached_parent_map([r1]))
 
2661
        self.assertEqual(
 
2662
            [('call_with_body_bytes_expecting_body',
 
2663
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2664
              '\n\n0')],
 
2665
            client._calls)
 
2666
        repo.unlock()
 
2667
 
2098
2668
 
2099
2669
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2670
 
2115
2685
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2686
 
2117
2687
 
 
2688
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2689
 
 
2690
    def test_hpss_missing_revision(self):
 
2691
        transport_path = 'quack'
 
2692
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2693
        client.add_success_response_with_body(
 
2694
            '', 'ok', '10')
 
2695
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2696
            ['somerev1', 'anotherrev2'])
 
2697
        self.assertEqual(
 
2698
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2699
             ('quack/', ), "somerev1\nanotherrev2")],
 
2700
            client._calls)
 
2701
 
 
2702
    def test_hpss_get_single_revision(self):
 
2703
        transport_path = 'quack'
 
2704
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2705
        somerev1 = Revision("somerev1")
 
2706
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2707
        somerev1.timestamp = 1321828927
 
2708
        somerev1.timezone = -60
 
2709
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2710
        somerev1.message = "Message"
 
2711
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2712
            somerev1))
 
2713
        # Split up body into two bits to make sure the zlib compression object
 
2714
        # gets data fed twice.
 
2715
        client.add_success_response_with_body(
 
2716
                [body[:10], body[10:]], 'ok', '10')
 
2717
        revs = repo.get_revisions(['somerev1'])
 
2718
        self.assertEquals(revs, [somerev1])
 
2719
        self.assertEqual(
 
2720
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2721
             ('quack/', ), "somerev1")],
 
2722
            client._calls)
 
2723
 
 
2724
 
2118
2725
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2726
 
2120
2727
    def test_null_revision(self):
2257
2864
        self.setup_smart_server_with_call_log()
2258
2865
        tree = self.make_branch_and_memory_tree('.')
2259
2866
        tree.lock_write()
 
2867
        tree.add('')
2260
2868
        rev1 = tree.commit('First')
2261
2869
        rev2 = tree.commit('Second')
2262
2870
        tree.unlock()
2270
2878
                              call.call.method == verb])
2271
2879
 
2272
2880
 
 
2881
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2882
 
 
2883
    def test_has_signature_for_revision_id(self):
 
2884
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2885
        transport_path = 'quack'
 
2886
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2887
        client.add_success_response('yes')
 
2888
        result = repo.has_signature_for_revision_id('A')
 
2889
        self.assertEqual(
 
2890
            [('call', 'Repository.has_signature_for_revision_id',
 
2891
              ('quack/', 'A'))],
 
2892
            client._calls)
 
2893
        self.assertEqual(True, result)
 
2894
 
 
2895
    def test_is_not_shared(self):
 
2896
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2897
        transport_path = 'qwack'
 
2898
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2899
        client.add_success_response('no')
 
2900
        result = repo.has_signature_for_revision_id('A')
 
2901
        self.assertEqual(
 
2902
            [('call', 'Repository.has_signature_for_revision_id',
 
2903
              ('qwack/', 'A'))],
 
2904
            client._calls)
 
2905
        self.assertEqual(False, result)
 
2906
 
 
2907
 
 
2908
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2909
 
 
2910
    def test_get_physical_lock_status_yes(self):
 
2911
        transport_path = 'qwack'
 
2912
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2913
        client.add_success_response('yes')
 
2914
        result = repo.get_physical_lock_status()
 
2915
        self.assertEqual(
 
2916
            [('call', 'Repository.get_physical_lock_status',
 
2917
              ('qwack/', ))],
 
2918
            client._calls)
 
2919
        self.assertEqual(True, result)
 
2920
 
 
2921
    def test_get_physical_lock_status_no(self):
 
2922
        transport_path = 'qwack'
 
2923
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2924
        client.add_success_response('no')
 
2925
        result = repo.get_physical_lock_status()
 
2926
        self.assertEqual(
 
2927
            [('call', 'Repository.get_physical_lock_status',
 
2928
              ('qwack/', ))],
 
2929
            client._calls)
 
2930
        self.assertEqual(False, result)
 
2931
 
 
2932
 
2273
2933
class TestRepositoryIsShared(TestRemoteRepository):
2274
2934
 
2275
2935
    def test_is_shared(self):
2295
2955
        self.assertEqual(False, result)
2296
2956
 
2297
2957
 
 
2958
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
2959
 
 
2960
    def test_make_working_trees(self):
 
2961
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
2962
        transport_path = 'quack'
 
2963
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2964
        client.add_success_response('yes')
 
2965
        result = repo.make_working_trees()
 
2966
        self.assertEqual(
 
2967
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
2968
            client._calls)
 
2969
        self.assertEqual(True, result)
 
2970
 
 
2971
    def test_no_working_trees(self):
 
2972
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
2973
        transport_path = 'qwack'
 
2974
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2975
        client.add_success_response('no')
 
2976
        result = repo.make_working_trees()
 
2977
        self.assertEqual(
 
2978
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
2979
            client._calls)
 
2980
        self.assertEqual(False, result)
 
2981
 
 
2982
 
2298
2983
class TestRepositoryLockWrite(TestRemoteRepository):
2299
2984
 
2300
2985
    def test_lock_write(self):
2301
2986
        transport_path = 'quack'
2302
2987
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
2988
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
2989
        token = repo.lock_write().repository_token
2305
2990
        self.assertEqual(
2306
2991
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
2992
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
2993
        self.assertEqual('a token', token)
2309
2994
 
2310
2995
    def test_lock_write_already_locked(self):
2311
2996
        transport_path = 'quack'
2326
3011
            client._calls)
2327
3012
 
2328
3013
 
 
3014
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3015
 
 
3016
    def test_start_write_group(self):
 
3017
        transport_path = 'quack'
 
3018
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3019
        client.add_expected_call(
 
3020
            'Repository.lock_write', ('quack/', ''),
 
3021
            'success', ('ok', 'a token'))
 
3022
        client.add_expected_call(
 
3023
            'Repository.start_write_group', ('quack/', 'a token'),
 
3024
            'success', ('ok', ('token1', )))
 
3025
        repo.lock_write()
 
3026
        repo.start_write_group()
 
3027
 
 
3028
    def test_start_write_group_unsuspendable(self):
 
3029
        # Some repositories do not support suspending write
 
3030
        # groups. For those, fall back to the "real" repository.
 
3031
        transport_path = 'quack'
 
3032
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3033
        def stub_ensure_real():
 
3034
            client._calls.append(('_ensure_real',))
 
3035
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3036
        repo._ensure_real = stub_ensure_real
 
3037
        client.add_expected_call(
 
3038
            'Repository.lock_write', ('quack/', ''),
 
3039
            'success', ('ok', 'a token'))
 
3040
        client.add_expected_call(
 
3041
            'Repository.start_write_group', ('quack/', 'a token'),
 
3042
            'error', ('UnsuspendableWriteGroup',))
 
3043
        repo.lock_write()
 
3044
        repo.start_write_group()
 
3045
        self.assertEquals(client._calls[-2:], [ 
 
3046
            ('_ensure_real',),
 
3047
            ('start_write_group',)])
 
3048
 
 
3049
    def test_commit_write_group(self):
 
3050
        transport_path = 'quack'
 
3051
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3052
        client.add_expected_call(
 
3053
            'Repository.lock_write', ('quack/', ''),
 
3054
            'success', ('ok', 'a token'))
 
3055
        client.add_expected_call(
 
3056
            'Repository.start_write_group', ('quack/', 'a token'),
 
3057
            'success', ('ok', ['token1']))
 
3058
        client.add_expected_call(
 
3059
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3060
            'success', ('ok',))
 
3061
        repo.lock_write()
 
3062
        repo.start_write_group()
 
3063
        repo.commit_write_group()
 
3064
 
 
3065
    def test_abort_write_group(self):
 
3066
        transport_path = 'quack'
 
3067
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3068
        client.add_expected_call(
 
3069
            'Repository.lock_write', ('quack/', ''),
 
3070
            'success', ('ok', 'a token'))
 
3071
        client.add_expected_call(
 
3072
            'Repository.start_write_group', ('quack/', 'a token'),
 
3073
            'success', ('ok', ['token1']))
 
3074
        client.add_expected_call(
 
3075
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3076
            'success', ('ok',))
 
3077
        repo.lock_write()
 
3078
        repo.start_write_group()
 
3079
        repo.abort_write_group(False)
 
3080
 
 
3081
    def test_suspend_write_group(self):
 
3082
        transport_path = 'quack'
 
3083
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3084
        self.assertEquals([], repo.suspend_write_group())
 
3085
 
 
3086
    def test_resume_write_group(self):
 
3087
        transport_path = 'quack'
 
3088
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3089
        client.add_expected_call(
 
3090
            'Repository.lock_write', ('quack/', ''),
 
3091
            'success', ('ok', 'a token'))
 
3092
        client.add_expected_call(
 
3093
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3094
            'success', ('ok',))
 
3095
        repo.lock_write()
 
3096
        repo.resume_write_group(['token1'])
 
3097
 
 
3098
 
2329
3099
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3100
 
2331
3101
    def test_backwards_compat(self):
2390
3160
        self.assertEqual([], client._calls)
2391
3161
 
2392
3162
 
 
3163
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3164
    """Test Repository.iter_file_bytes."""
 
3165
 
 
3166
    def test_single(self):
 
3167
        transport_path = 'quack'
 
3168
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3169
        client.add_expected_call(
 
3170
            'Repository.iter_files_bytes', ('quack/', ),
 
3171
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3172
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3173
                "somerev", "myid")]):
 
3174
            self.assertEquals("myid", identifier)
 
3175
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3176
 
 
3177
    def test_missing(self):
 
3178
        transport_path = 'quack'
 
3179
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3180
        client.add_expected_call(
 
3181
            'Repository.iter_files_bytes',
 
3182
                ('quack/', ),
 
3183
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3184
            iter(["absent\0somefile\0somerev\n"]))
 
3185
        self.assertRaises(errors.RevisionNotPresent, list,
 
3186
                repo.iter_files_bytes(
 
3187
                [("somefile", "somerev", "myid")]))
 
3188
 
 
3189
 
2393
3190
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3191
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3192
    tests.
2402
3199
        the client is finished.
2403
3200
        """
2404
3201
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3202
        fmt = repository.format_registry.get_default()
2406
3203
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3204
        self.assertEqual([], resume_tokens)
2408
3205
        self.assertEqual(set(), missing_keys)
2508
3305
                return True
2509
3306
        repo._real_repository = FakeRealRepository()
2510
3307
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3308
        fmt = repository.format_registry.get_default()
2512
3309
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3310
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3311
        # Every record from the first inventory delta should have been sent to
2670
3467
        self.calls = calls
2671
3468
        self._pack_collection = _StubPackCollection(calls)
2672
3469
 
 
3470
    def start_write_group(self):
 
3471
        self.calls.append(('start_write_group',))
 
3472
 
2673
3473
    def is_in_write_group(self):
2674
3474
        return False
2675
3475
 
2734
3534
             ('pack collection autopack',)],
2735
3535
            client._calls)
2736
3536
 
 
3537
    def test_oom_error_reporting(self):
 
3538
        """An out-of-memory condition on the server is reported clearly"""
 
3539
        transport_path = 'quack'
 
3540
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3541
        client.add_expected_call(
 
3542
            'PackRepository.autopack', ('quack/',),
 
3543
            'error', ('MemoryError',))
 
3544
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3545
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3546
 
2737
3547
 
2738
3548
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3549
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3622
            detail='extra detail')
2813
3623
        self.assertEqual(expected_error, translated_error)
2814
3624
 
 
3625
    def test_norepository(self):
 
3626
        bzrdir = self.make_bzrdir('')
 
3627
        translated_error = self.translateTuple(('norepository',),
 
3628
            bzrdir=bzrdir)
 
3629
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3630
        self.assertEqual(expected_error, translated_error)
 
3631
 
2815
3632
    def test_LockContention(self):
2816
3633
        translated_error = self.translateTuple(('LockContention',))
2817
3634
        expected_error = errors.LockContention('(remote lock)')
2845
3662
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3663
        self.assertEqual(expected_error, translated_error)
2847
3664
 
 
3665
    def test_NotStacked(self):
 
3666
        branch = self.make_branch('')
 
3667
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3668
        expected_error = errors.NotStacked(branch)
 
3669
        self.assertEqual(expected_error, translated_error)
 
3670
 
2848
3671
    def test_ReadError_no_args(self):
2849
3672
        path = 'a path'
2850
3673
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3689
 
2867
3690
    def test_PermissionDenied_no_args(self):
2868
3691
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3692
        translated_error = self.translateTuple(('PermissionDenied',),
 
3693
            path=path)
2870
3694
        expected_error = errors.PermissionDenied(path)
2871
3695
        self.assertEqual(expected_error, translated_error)
2872
3696
 
2895
3719
        expected_error = errors.PermissionDenied(path, extra)
2896
3720
        self.assertEqual(expected_error, translated_error)
2897
3721
 
 
3722
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3723
 
 
3724
    def test_NoSuchFile_context_path(self):
 
3725
        local_path = "local path"
 
3726
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3727
            path=local_path)
 
3728
        expected_error = errors.ReadError(local_path)
 
3729
        self.assertEqual(expected_error, translated_error)
 
3730
 
 
3731
    def test_NoSuchFile_without_context(self):
 
3732
        remote_path = "remote path"
 
3733
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3734
        expected_error = errors.ReadError(remote_path)
 
3735
        self.assertEqual(expected_error, translated_error)
 
3736
 
 
3737
    def test_ReadOnlyError(self):
 
3738
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3739
        expected_error = errors.TransportNotPossible("readonly transport")
 
3740
        self.assertEqual(expected_error, translated_error)
 
3741
 
 
3742
    def test_MemoryError(self):
 
3743
        translated_error = self.translateTuple(('MemoryError',))
 
3744
        self.assertStartsWith(str(translated_error),
 
3745
            "remote server out of memory")
 
3746
 
 
3747
    def test_generic_IndexError_no_classname(self):
 
3748
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3749
        translated_error = self.translateErrorFromSmartServer(err)
 
3750
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3751
        self.assertEqual(expected_error, translated_error)
 
3752
 
 
3753
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3754
 
 
3755
    def test_generic_KeyError(self):
 
3756
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3757
        translated_error = self.translateErrorFromSmartServer(err)
 
3758
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3759
        self.assertEqual(expected_error, translated_error)
 
3760
 
2898
3761
 
2899
3762
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3763
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3908
        _, stacked = branch_factory()
3046
3909
        source = stacked.repository._get_source(target_repository_format)
3047
3910
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3911
        stacked.repository._ensure_real()
 
3912
        graph = stacked.repository.get_graph()
 
3913
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3914
                if r != NULL_REVISION]
 
3915
        revs.reverse()
 
3916
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3917
        self.reset_smart_call_log()
3051
3918
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3919
        # We trust that if a revision is in the stream the rest of the new
3055
3920
        # content for it is too, as per our main fetch tests; here we are
3056
3921
        # checking that the revisions are actually included at all, and their
3095
3960
        self.assertEqual(expected_revs, rev_ord)
3096
3961
        # Getting topological sort requires VFS calls still - one of which is
3097
3962
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
3963
        self.assertLength(14, self.hpss_calls)
3099
3964
 
3100
3965
    def test_stacked_get_stream_groupcompress(self):
3101
3966
        # Repository._get_source.get_stream() from a stacked repository with
3142
4007
 
3143
4008
    def test_copy_content_into_avoids_revision_history(self):
3144
4009
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4010
        builder = self.make_branch_builder('remote')
 
4011
        builder.build_commit(message="Commit.")
3147
4012
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4013
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4014
        local.repository.fetch(remote_branch.repository)
3150
4015
        self.hpss_calls = []
3151
4016
        remote_branch.copy_content_into(local)
3152
4017
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4018
 
 
4019
    def test_fetch_everything_needs_just_one_call(self):
 
4020
        local = self.make_branch('local')
 
4021
        builder = self.make_branch_builder('remote')
 
4022
        builder.build_commit(message="Commit.")
 
4023
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4024
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4025
        self.hpss_calls = []
 
4026
        local.repository.fetch(
 
4027
            remote_branch.repository,
 
4028
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4029
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4030
 
 
4031
    def override_verb(self, verb_name, verb):
 
4032
        request_handlers = request.request_handlers
 
4033
        orig_verb = request_handlers.get(verb_name)
 
4034
        orig_info = request_handlers.get_info(verb_name)
 
4035
        request_handlers.register(verb_name, verb, override_existing=True)
 
4036
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4037
                override_existing=True, info=orig_info)
 
4038
 
 
4039
    def test_fetch_everything_backwards_compat(self):
 
4040
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4041
        
 
4042
        Pre-2.4 do not support 'everything' searches with the
 
4043
        Repository.get_stream_1.19 verb.
 
4044
        """
 
4045
        verb_log = []
 
4046
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4047
            """A version of the Repository.get_stream_1.19 verb patched to
 
4048
            reject 'everything' searches the way 2.3 and earlier do.
 
4049
            """
 
4050
            def recreate_search(self, repository, search_bytes,
 
4051
                                discard_excess=False):
 
4052
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4053
                if search_bytes == 'everything':
 
4054
                    return (None,
 
4055
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4056
                return super(OldGetStreamVerb,
 
4057
                        self).recreate_search(repository, search_bytes,
 
4058
                            discard_excess=discard_excess)
 
4059
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4060
        local = self.make_branch('local')
 
4061
        builder = self.make_branch_builder('remote')
 
4062
        builder.build_commit(message="Commit.")
 
4063
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4064
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4065
        self.hpss_calls = []
 
4066
        local.repository.fetch(
 
4067
            remote_branch.repository,
 
4068
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4069
        # make sure the overridden verb was used
 
4070
        self.assertLength(1, verb_log)
 
4071
        # more than one HPSS call is needed, but because it's a VFS callback
 
4072
        # its hard to predict exactly how many.
 
4073
        self.assertTrue(len(self.hpss_calls) > 1)
 
4074
 
 
4075
 
 
4076
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4077
    tests.TestCaseWithTransport):
 
4078
    """Ensure correct handling of bound_location modifications.
 
4079
 
 
4080
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4081
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4082
    happen in this context.
 
4083
    """
 
4084
 
 
4085
    def setUp(self):
 
4086
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4087
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4088
 
 
4089
    def make_master_and_checkout(self, master_name, checkout_name):
 
4090
        # Create the master branch and its associated checkout
 
4091
        self.master = self.make_branch_and_tree(master_name)
 
4092
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4093
        # Modify the master branch so there is something to update
 
4094
        self.master.commit('add stuff')
 
4095
        self.last_revid = self.master.commit('even more stuff')
 
4096
        self.bound_location = self.checkout.branch.get_bound_location()
 
4097
 
 
4098
    def assertUpdateSucceeds(self, new_location):
 
4099
        self.checkout.branch.set_bound_location(new_location)
 
4100
        self.checkout.update()
 
4101
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4102
 
 
4103
    def test_without_final_slash(self):
 
4104
        self.make_master_and_checkout('master', 'checkout')
 
4105
        # For unclear reasons some users have a bound_location without a final
 
4106
        # '/', simulate that by forcing such a value
 
4107
        self.assertEndsWith(self.bound_location, '/')
 
4108
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4109
 
 
4110
    def test_plus_sign(self):
 
4111
        self.make_master_and_checkout('+master', 'checkout')
 
4112
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4113
 
 
4114
    def test_tilda(self):
 
4115
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4116
        # interpretation
 
4117
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4118
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4119
 
 
4120
 
 
4121
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4122
 
 
4123
    def test_no_context(self):
 
4124
        class OutOfCoffee(errors.BzrError):
 
4125
            """A dummy exception for testing."""
 
4126
 
 
4127
            def __init__(self, urgency):
 
4128
                self.urgency = urgency
 
4129
        remote.no_context_error_translators.register("OutOfCoffee",
 
4130
            lambda err: OutOfCoffee(err.error_args[0]))
 
4131
        transport = MemoryTransport()
 
4132
        client = FakeClient(transport.base)
 
4133
        client.add_expected_call(
 
4134
            'Branch.get_stacked_on_url', ('quack/',),
 
4135
            'error', ('NotStacked',))
 
4136
        client.add_expected_call(
 
4137
            'Branch.last_revision_info',
 
4138
            ('quack/',),
 
4139
            'error', ('OutOfCoffee', 'low'))
 
4140
        transport.mkdir('quack')
 
4141
        transport = transport.clone('quack')
 
4142
        branch = self.make_remote_branch(transport, client)
 
4143
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4144
        self.assertFinished(client)
 
4145
 
 
4146
    def test_with_context(self):
 
4147
        class OutOfTea(errors.BzrError):
 
4148
            def __init__(self, branch, urgency):
 
4149
                self.branch = branch
 
4150
                self.urgency = urgency
 
4151
        remote.error_translators.register("OutOfTea",
 
4152
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4153
                find("branch")))
 
4154
        transport = MemoryTransport()
 
4155
        client = FakeClient(transport.base)
 
4156
        client.add_expected_call(
 
4157
            'Branch.get_stacked_on_url', ('quack/',),
 
4158
            'error', ('NotStacked',))
 
4159
        client.add_expected_call(
 
4160
            'Branch.last_revision_info',
 
4161
            ('quack/',),
 
4162
            'error', ('OutOfTea', 'low'))
 
4163
        transport.mkdir('quack')
 
4164
        transport = transport.clone('quack')
 
4165
        branch = self.make_remote_branch(transport, client)
 
4166
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4167
        self.assertFinished(client)
 
4168
 
 
4169
 
 
4170
class TestRepositoryPack(TestRemoteRepository):
 
4171
 
 
4172
    def test_pack(self):
 
4173
        transport_path = 'quack'
 
4174
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4175
        client.add_expected_call(
 
4176
            'Repository.lock_write', ('quack/', ''),
 
4177
            'success', ('ok', 'token'))
 
4178
        client.add_expected_call(
 
4179
            'Repository.pack', ('quack/', 'token', 'False'),
 
4180
            'success', ('ok',), )
 
4181
        client.add_expected_call(
 
4182
            'Repository.unlock', ('quack/', 'token'),
 
4183
            'success', ('ok', ))
 
4184
        repo.pack()
 
4185
 
 
4186
    def test_pack_with_hint(self):
 
4187
        transport_path = 'quack'
 
4188
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4189
        client.add_expected_call(
 
4190
            'Repository.lock_write', ('quack/', ''),
 
4191
            'success', ('ok', 'token'))
 
4192
        client.add_expected_call(
 
4193
            'Repository.pack', ('quack/', 'token', 'False'),
 
4194
            'success', ('ok',), )
 
4195
        client.add_expected_call(
 
4196
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4197
            'success', ('ok', ))
 
4198
        repo.pack(['hinta', 'hintb'])