/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

  • Committer: Martin Pool
  • Date: 2011-11-29 00:50:36 UTC
  • mto: This revision was merged to the branch mainline in revision 6320.
  • Revision ID: mbp@canonical.com-20111129005036-1vopao4wm0yo9ekn
Slight cleanup of TimeoutFixture

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