/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: Jelmer Vernooij
  • Date: 2011-12-14 12:25:34 UTC
  • mto: (6282.6.42 hpss-get-inventories)
  • mto: This revision was merged to the branch mainline in revision 6371.
  • Revision ID: jelmer@samba.org-20111214122534-5ot01rv7miypacmf
More documentation.

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 TestBzrDirCheckoutMetaDir(TestRemote):
 
507
 
 
508
    def test__get_checkout_format(self):
 
509
        transport = MemoryTransport()
 
510
        client = FakeClient(transport.base)
 
511
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
512
        control_name = reference_bzrdir_format.network_name()
 
513
        client.add_expected_call(
 
514
            'BzrDir.checkout_metadir', ('quack/', ),
 
515
            'success', (control_name, '', ''))
 
516
        transport.mkdir('quack')
 
517
        transport = transport.clone('quack')
 
518
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
519
            _client=client)
 
520
        result = a_bzrdir.checkout_metadir()
 
521
        # We should have got a reference control dir with default branch and
 
522
        # repository formats.
 
523
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
524
        self.assertEqual(None, result._repository_format)
 
525
        self.assertEqual(None, result._branch_format)
 
526
        self.assertFinished(client)
 
527
 
 
528
    def test_unknown_format(self):
 
529
        transport = MemoryTransport()
 
530
        client = FakeClient(transport.base)
 
531
        client.add_expected_call(
 
532
            'BzrDir.checkout_metadir', ('quack/',),
 
533
            'success', ('dontknow', '', ''))
 
534
        transport.mkdir('quack')
 
535
        transport = transport.clone('quack')
 
536
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
537
            _client=client)
 
538
        self.assertRaises(errors.UnknownFormatError,
 
539
            a_bzrdir.checkout_metadir)
 
540
        self.assertFinished(client)
 
541
 
 
542
 
 
543
class TestBzrDirDestroyBranch(TestRemote):
 
544
 
 
545
    def test_destroy_default(self):
 
546
        transport = self.get_transport('quack')
 
547
        referenced = self.make_branch('referenced')
 
548
        client = FakeClient(transport.base)
 
549
        client.add_expected_call(
 
550
            'BzrDir.destroy_branch', ('quack/', ),
 
551
            'success', ('ok',)),
 
552
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
553
            _client=client)
 
554
        a_bzrdir.destroy_branch()
 
555
        self.assertFinished(client)
 
556
 
 
557
    def test_destroy_named(self):
 
558
        transport = self.get_transport('quack')
 
559
        referenced = self.make_branch('referenced')
 
560
        client = FakeClient(transport.base)
 
561
        client.add_expected_call(
 
562
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
563
            'success', ('ok',)),
 
564
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
565
            _client=client)
 
566
        a_bzrdir.destroy_branch("foo")
 
567
        self.assertFinished(client)
 
568
 
 
569
 
 
570
class TestBzrDirHasWorkingTree(TestRemote):
 
571
 
 
572
    def test_has_workingtree(self):
 
573
        transport = self.get_transport('quack')
 
574
        client = FakeClient(transport.base)
 
575
        client.add_expected_call(
 
576
            'BzrDir.has_workingtree', ('quack/',),
 
577
            'success', ('yes',)),
 
578
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
579
            _client=client)
 
580
        self.assertTrue(a_bzrdir.has_workingtree())
 
581
        self.assertFinished(client)
 
582
 
 
583
    def test_no_workingtree(self):
 
584
        transport = self.get_transport('quack')
 
585
        client = FakeClient(transport.base)
 
586
        client.add_expected_call(
 
587
            'BzrDir.has_workingtree', ('quack/',),
 
588
            'success', ('no',)),
 
589
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
590
            _client=client)
 
591
        self.assertFalse(a_bzrdir.has_workingtree())
 
592
        self.assertFinished(client)
 
593
 
 
594
 
 
595
class TestBzrDirDestroyRepository(TestRemote):
 
596
 
 
597
    def test_destroy_repository(self):
 
598
        transport = self.get_transport('quack')
 
599
        client = FakeClient(transport.base)
 
600
        client.add_expected_call(
 
601
            'BzrDir.destroy_repository', ('quack/',),
 
602
            'success', ('ok',)),
 
603
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
604
            _client=client)
 
605
        a_bzrdir.destroy_repository()
 
606
        self.assertFinished(client)
 
607
 
483
608
 
484
609
class TestBzrDirOpen(TestRemote):
485
610
 
495
620
        client.add_expected_call(
496
621
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
622
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
623
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
624
        self.assertFinished(client)
500
625
 
501
626
    def test_present_without_workingtree(self):
502
627
        client, transport = self.make_fake_client_and_transport()
503
628
        client.add_expected_call(
504
629
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
630
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
631
            _client=client, _force_probe=True)
507
632
        self.assertIsInstance(bd, RemoteBzrDir)
508
633
        self.assertFalse(bd.has_workingtree())
513
638
        client, transport = self.make_fake_client_and_transport()
514
639
        client.add_expected_call(
515
640
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
641
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
642
            _client=client, _force_probe=True)
518
643
        self.assertIsInstance(bd, RemoteBzrDir)
519
644
        self.assertTrue(bd.has_workingtree())
526
651
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
652
        client.add_expected_call(
528
653
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
654
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
655
            _client=client, _force_probe=True)
531
656
        self.assertIsInstance(bd, RemoteBzrDir)
532
657
        self.assertFinished(client)
548
673
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
674
        client.add_expected_call(
550
675
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
676
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
677
            _client=client, _force_probe=True)
553
678
        self.assertIsInstance(bd, RemoteBzrDir)
554
679
        self.assertFinished(client)
585
710
        client.add_expected_call(
586
711
            'Branch.get_stacked_on_url', ('quack/',),
587
712
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
713
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
714
            _client=client)
590
715
        result = bzrdir.open_branch()
591
716
        self.assertIsInstance(result, RemoteBranch)
598
723
        transport = transport.clone('quack')
599
724
        client = FakeClient(transport.base)
600
725
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
726
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
727
            _client=client)
603
728
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
729
        self.assertEqual(
609
734
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
735
        # branch opening, not any other network requests.
611
736
        calls = []
612
 
        def open_branch():
 
737
        def open_branch(name=None, possible_transports=None):
613
738
            calls.append("Called")
614
739
            return "a-branch"
615
740
        transport = MemoryTransport()
616
741
        # no requests on the network - catches other api calls being made.
617
742
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
743
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
744
            _client=client)
620
745
        # patch the open_branch call to record that it was called.
621
746
        bzrdir.open_branch = open_branch
640
765
        client.add_expected_call(
641
766
            'Branch.get_stacked_on_url', ('~hello/',),
642
767
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
768
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
769
            _client=client)
645
770
        result = bzrdir.open_branch()
646
771
        self.assertFinished(client)
663
788
        client.add_success_response(
664
789
            'ok', '', rich_response, subtree_response, external_lookup,
665
790
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
791
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
792
            _client=client)
668
793
        result = bzrdir.open_repository()
669
794
        self.assertEqual(
686
811
        old.
687
812
        """
688
813
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
814
            RemoteBzrProber.probe_transport, OldServerTransport())
690
815
 
691
816
 
692
817
class TestBzrDirCreateBranch(TestRemote):
715
840
            'BzrDir.create_branch', ('quack/', network_name),
716
841
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
842
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
843
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
844
            _client=client)
720
845
        branch = a_bzrdir.create_branch()
721
846
        # We should have got a remote branch
724
849
        format = branch._format
725
850
        self.assertEqual(network_name, format.network_name())
726
851
 
 
852
    def test_already_open_repo_and_reused_medium(self):
 
853
        """Bug 726584: create_branch(..., repository=repo) should work
 
854
        regardless of what the smart medium's base URL is.
 
855
        """
 
856
        self.transport_server = test_server.SmartTCPServer_for_testing
 
857
        transport = self.get_transport('.')
 
858
        repo = self.make_repository('quack')
 
859
        # Client's medium rooted a transport root (not at the bzrdir)
 
860
        client = FakeClient(transport.base)
 
861
        transport = transport.clone('quack')
 
862
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
863
        reference_format = reference_bzrdir_format.get_branch_format()
 
864
        network_name = reference_format.network_name()
 
865
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
866
        reference_repo_name = reference_repo_fmt.network_name()
 
867
        client.add_expected_call(
 
868
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
869
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
870
            reference_repo_name))
 
871
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
872
            _client=client)
 
873
        branch = a_bzrdir.create_branch(repository=repo)
 
874
        # We should have got a remote branch
 
875
        self.assertIsInstance(branch, remote.RemoteBranch)
 
876
        # its format should have the settings from the response
 
877
        format = branch._format
 
878
        self.assertEqual(network_name, format.network_name())
 
879
 
727
880
 
728
881
class TestBzrDirCreateRepository(TestRemote):
729
882
 
750
903
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
904
                'False'),
752
905
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
906
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
907
            _client=client)
755
908
        repo = a_bzrdir.create_repository()
756
909
        # We should have got a remote repository
785
938
        client.add_success_response('stat', '0', '65535')
786
939
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
940
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
941
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
942
            _client=client)
790
943
        repo = bzrdir.open_repository()
791
944
        self.assertEqual(
818
971
        client.add_success_response('stat', '0', '65535')
819
972
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
973
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
974
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
975
            _client=client)
823
976
        repo = bzrdir.open_repository()
824
977
        self.assertEqual(
839
992
        transport = transport.clone('quack')
840
993
        client = FakeClient(transport.base)
841
994
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
995
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
996
            _client=client)
844
997
        repo = bzrdir.open_repository()
845
998
        self.assertEqual(
852
1005
 
853
1006
    def test_success(self):
854
1007
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1008
        fmt = RemoteBzrDirFormat()
856
1009
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1010
        transport = self.get_transport()
858
1011
        client = FakeClient(transport.base)
874
1027
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1028
        corresponding error from the client.
876
1029
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1030
        fmt = RemoteBzrDirFormat()
878
1031
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1032
        transport = self.get_transport()
880
1033
        client = FakeClient(transport.base)
898
1051
        """Integration test for error translation."""
899
1052
        transport = self.make_smart_server('foo')
900
1053
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1054
        fmt = RemoteBzrDirFormat()
902
1055
        err = self.assertRaises(errors.NoSuchFile,
903
1056
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1057
 
935
1088
 
936
1089
    def make_remote_bzrdir(self, transport, client):
937
1090
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1091
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1092
            _client=client)
940
1093
 
941
1094
 
967
1120
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1121
 
969
1122
 
 
1123
class TestBranchBreakLock(RemoteBranchTestCase):
 
1124
 
 
1125
    def test_break_lock(self):
 
1126
        transport_path = 'quack'
 
1127
        transport = MemoryTransport()
 
1128
        client = FakeClient(transport.base)
 
1129
        client.add_expected_call(
 
1130
            'Branch.get_stacked_on_url', ('quack/',),
 
1131
            'error', ('NotStacked',))
 
1132
        client.add_expected_call(
 
1133
            'Branch.break_lock', ('quack/',),
 
1134
            'success', ('ok',))
 
1135
        transport.mkdir('quack')
 
1136
        transport = transport.clone('quack')
 
1137
        branch = self.make_remote_branch(transport, client)
 
1138
        branch.break_lock()
 
1139
        self.assertFinished(client)
 
1140
 
 
1141
 
 
1142
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1143
 
 
1144
    def test_get_physical_lock_status_yes(self):
 
1145
        transport = MemoryTransport()
 
1146
        client = FakeClient(transport.base)
 
1147
        client.add_expected_call(
 
1148
            'Branch.get_stacked_on_url', ('quack/',),
 
1149
            'error', ('NotStacked',))
 
1150
        client.add_expected_call(
 
1151
            'Branch.get_physical_lock_status', ('quack/',),
 
1152
            'success', ('yes',))
 
1153
        transport.mkdir('quack')
 
1154
        transport = transport.clone('quack')
 
1155
        branch = self.make_remote_branch(transport, client)
 
1156
        result = branch.get_physical_lock_status()
 
1157
        self.assertFinished(client)
 
1158
        self.assertEqual(True, result)
 
1159
 
 
1160
    def test_get_physical_lock_status_no(self):
 
1161
        transport = MemoryTransport()
 
1162
        client = FakeClient(transport.base)
 
1163
        client.add_expected_call(
 
1164
            'Branch.get_stacked_on_url', ('quack/',),
 
1165
            'error', ('NotStacked',))
 
1166
        client.add_expected_call(
 
1167
            'Branch.get_physical_lock_status', ('quack/',),
 
1168
            'success', ('no',))
 
1169
        transport.mkdir('quack')
 
1170
        transport = transport.clone('quack')
 
1171
        branch = self.make_remote_branch(transport, client)
 
1172
        result = branch.get_physical_lock_status()
 
1173
        self.assertFinished(client)
 
1174
        self.assertEqual(False, result)
 
1175
 
 
1176
 
970
1177
class TestBranchGetParent(RemoteBranchTestCase):
971
1178
 
972
1179
    def test_no_parent(self):
1143
1350
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1351
 
1145
1352
 
 
1353
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1354
 
 
1355
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1356
        transport = MemoryTransport()
 
1357
        client = FakeClient(transport.base)
 
1358
        client.add_expected_call(
 
1359
            'Branch.get_stacked_on_url', ('quack/',),
 
1360
            'error', ('NotStacked',))
 
1361
        client.add_expected_call(
 
1362
            'Branch.last_revision_info', ('quack/',),
 
1363
            'success', ('ok', '1', 'rev-tip'))
 
1364
        client.add_expected_call(
 
1365
            'Branch.get_config_file', ('quack/',),
 
1366
            'success', ('ok',), '')
 
1367
        transport.mkdir('quack')
 
1368
        transport = transport.clone('quack')
 
1369
        branch = self.make_remote_branch(transport, client)
 
1370
        result = branch.heads_to_fetch()
 
1371
        self.assertFinished(client)
 
1372
        self.assertEqual((set(['rev-tip']), set()), result)
 
1373
 
 
1374
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1375
        transport = MemoryTransport()
 
1376
        client = FakeClient(transport.base)
 
1377
        client.add_expected_call(
 
1378
            'Branch.get_stacked_on_url', ('quack/',),
 
1379
            'error', ('NotStacked',))
 
1380
        client.add_expected_call(
 
1381
            'Branch.last_revision_info', ('quack/',),
 
1382
            'success', ('ok', '1', 'rev-tip'))
 
1383
        client.add_expected_call(
 
1384
            'Branch.get_config_file', ('quack/',),
 
1385
            'success', ('ok',), 'branch.fetch_tags = True')
 
1386
        # XXX: this will break if the default format's serialization of tags
 
1387
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1388
        client.add_expected_call(
 
1389
            'Branch.get_tags_bytes', ('quack/',),
 
1390
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1391
        transport.mkdir('quack')
 
1392
        transport = transport.clone('quack')
 
1393
        branch = self.make_remote_branch(transport, client)
 
1394
        result = branch.heads_to_fetch()
 
1395
        self.assertFinished(client)
 
1396
        self.assertEqual(
 
1397
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1398
 
 
1399
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1400
        transport = MemoryTransport()
 
1401
        client = FakeClient(transport.base)
 
1402
        client.add_expected_call(
 
1403
            'Branch.get_stacked_on_url', ('quack/',),
 
1404
            'error', ('NotStacked',))
 
1405
        client.add_expected_call(
 
1406
            'Branch.heads_to_fetch', ('quack/',),
 
1407
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1408
        transport.mkdir('quack')
 
1409
        transport = transport.clone('quack')
 
1410
        branch = self.make_remote_branch(transport, client)
 
1411
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1412
        result = branch.heads_to_fetch()
 
1413
        self.assertFinished(client)
 
1414
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1415
 
 
1416
    def make_branch_with_tags(self):
 
1417
        self.setup_smart_server_with_call_log()
 
1418
        # Make a branch with a single revision.
 
1419
        builder = self.make_branch_builder('foo')
 
1420
        builder.start_series()
 
1421
        builder.build_snapshot('tip', None, [
 
1422
            ('add', ('', 'root-id', 'directory', ''))])
 
1423
        builder.finish_series()
 
1424
        branch = builder.get_branch()
 
1425
        # Add two tags to that branch
 
1426
        branch.tags.set_tag('tag-1', 'rev-1')
 
1427
        branch.tags.set_tag('tag-2', 'rev-2')
 
1428
        return branch
 
1429
 
 
1430
    def test_backwards_compatible(self):
 
1431
        branch = self.make_branch_with_tags()
 
1432
        c = branch.get_config()
 
1433
        c.set_user_option('branch.fetch_tags', 'True')
 
1434
        self.addCleanup(branch.lock_read().unlock)
 
1435
        # Disable the heads_to_fetch verb
 
1436
        verb = 'Branch.heads_to_fetch'
 
1437
        self.disable_verb(verb)
 
1438
        self.reset_smart_call_log()
 
1439
        result = branch.heads_to_fetch()
 
1440
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1441
        self.assertEqual(
 
1442
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1443
             'Branch.get_tags_bytes'],
 
1444
            [call.call.method for call in self.hpss_calls])
 
1445
 
 
1446
    def test_backwards_compatible_no_tags(self):
 
1447
        branch = self.make_branch_with_tags()
 
1448
        c = branch.get_config()
 
1449
        c.set_user_option('branch.fetch_tags', 'False')
 
1450
        self.addCleanup(branch.lock_read().unlock)
 
1451
        # Disable the heads_to_fetch verb
 
1452
        verb = 'Branch.heads_to_fetch'
 
1453
        self.disable_verb(verb)
 
1454
        self.reset_smart_call_log()
 
1455
        result = branch.heads_to_fetch()
 
1456
        self.assertEqual((set(['tip']), set()), result)
 
1457
        self.assertEqual(
 
1458
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1459
            [call.call.method for call in self.hpss_calls])
 
1460
 
 
1461
 
1146
1462
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1463
 
1148
1464
    def test_empty_branch(self):
1203
1519
        client.add_expected_call(
1204
1520
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1521
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1522
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1523
            _client=client)
1208
1524
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1525
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1552
        # this will also do vfs access, but that goes direct to the transport
1237
1553
        # and isn't seen by the FakeClient.
1238
1554
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1555
            RemoteBzrDirFormat(), _client=client)
1240
1556
        branch = bzrdir.open_branch()
1241
1557
        result = branch.get_stacked_on_url()
1242
1558
        self.assertEqual('../base', result)
1269
1585
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1586
            'success', ('ok', '../base'))
1271
1587
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1588
            RemoteBzrDirFormat(), _client=client)
1273
1589
        branch = bzrdir.open_branch()
1274
1590
        result = branch.get_stacked_on_url()
1275
1591
        self.assertEqual('../base', result)
1283
1599
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1600
 
1285
1601
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1602
        # _set_last_revision_info('null:') is translated to calling
1287
1603
        # Branch.set_last_revision(path, '') on the wire.
1288
1604
        transport = MemoryTransport()
1289
1605
        transport.mkdir('branch')
1307
1623
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1624
            'success', ('ok',))
1309
1625
        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
1626
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1627
        result = branch._set_last_revision(NULL_REVISION)
1315
1628
        branch.unlock()
1316
1629
        self.assertEqual(None, result)
1317
1630
        self.assertFinished(client)
1318
1631
 
1319
1632
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1633
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1634
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1635
        transport = MemoryTransport()
1323
1636
        transport.mkdir('branch')
1344
1657
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1658
            'success', ('ok',))
1346
1659
        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
1660
        # Lock the branch, reset the record of remote calls.
1351
1661
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1662
        result = branch._set_last_revision('rev-id2')
1353
1663
        branch.unlock()
1354
1664
        self.assertEqual(None, result)
1355
1665
        self.assertFinished(client)
1385
1695
        branch = self.make_remote_branch(transport, client)
1386
1696
        branch.lock_write()
1387
1697
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1698
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1699
        branch.unlock()
1390
1700
        self.assertFinished(client)
1391
1701
 
1419
1729
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1730
            'success', ('ok',))
1421
1731
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1732
        branch.lock_write()
1424
1733
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1734
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1735
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1736
            errors.TipChangeRejected,
 
1737
            branch._set_last_revision, 'rev-id')
1428
1738
        # The UTF-8 message from the response has been decoded into a unicode
1429
1739
        # object.
1430
1740
        self.assertIsInstance(err.msg, unicode)
1618
1928
    def test_get_multi_line_branch_conf(self):
1619
1929
        # Make sure that multiple-line branch.conf files are supported
1620
1930
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1931
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1932
        client = FakeClient()
1623
1933
        client.add_expected_call(
1624
1934
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1962
        branch.unlock()
1653
1963
        self.assertFinished(client)
1654
1964
 
 
1965
    def test_set_option_with_dict(self):
 
1966
        client = FakeClient()
 
1967
        client.add_expected_call(
 
1968
            'Branch.get_stacked_on_url', ('memory:///',),
 
1969
            'error', ('NotStacked',),)
 
1970
        client.add_expected_call(
 
1971
            'Branch.lock_write', ('memory:///', '', ''),
 
1972
            'success', ('ok', 'branch token', 'repo token'))
 
1973
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1974
        client.add_expected_call(
 
1975
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1976
            'repo token', encoded_dict_value, 'foo', ''),
 
1977
            'success', ())
 
1978
        client.add_expected_call(
 
1979
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1980
            'success', ('ok',))
 
1981
        transport = MemoryTransport()
 
1982
        branch = self.make_remote_branch(transport, client)
 
1983
        branch.lock_write()
 
1984
        config = branch._get_config()
 
1985
        config.set_option(
 
1986
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1987
            'foo')
 
1988
        branch.unlock()
 
1989
        self.assertFinished(client)
 
1990
 
1655
1991
    def test_backwards_compat_set_option(self):
1656
1992
        self.setup_smart_server_with_call_log()
1657
1993
        branch = self.make_branch('.')
1664
2000
        self.assertLength(10, self.hpss_calls)
1665
2001
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2002
 
 
2003
    def test_backwards_compat_set_option_with_dict(self):
 
2004
        self.setup_smart_server_with_call_log()
 
2005
        branch = self.make_branch('.')
 
2006
        verb = 'Branch.set_config_option_dict'
 
2007
        self.disable_verb(verb)
 
2008
        branch.lock_write()
 
2009
        self.addCleanup(branch.unlock)
 
2010
        self.reset_smart_call_log()
 
2011
        config = branch._get_config()
 
2012
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2013
        config.set_option(value_dict, 'name')
 
2014
        self.assertLength(10, self.hpss_calls)
 
2015
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2016
 
 
2017
 
 
2018
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2019
 
 
2020
    def test_get_branch_conf(self):
 
2021
        # in an empty branch we decode the response properly
 
2022
        client = FakeClient()
 
2023
        client.add_expected_call(
 
2024
            'Branch.get_stacked_on_url', ('memory:///',),
 
2025
            'error', ('NotStacked',),)
 
2026
        client.add_success_response_with_body('# config file body', 'ok')
 
2027
        transport = MemoryTransport()
 
2028
        branch = self.make_remote_branch(transport, client)
 
2029
        config = branch.get_config_stack()
 
2030
        config.get("email")
 
2031
        config.get("log_format")
 
2032
        self.assertEqual(
 
2033
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2034
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2035
            client._calls)
 
2036
 
 
2037
    def test_set_branch_conf(self):
 
2038
        client = FakeClient()
 
2039
        client.add_expected_call(
 
2040
            'Branch.get_stacked_on_url', ('memory:///',),
 
2041
            'error', ('NotStacked',),)
 
2042
        client.add_expected_call(
 
2043
            'Branch.lock_write', ('memory:///', '', ''),
 
2044
            'success', ('ok', 'branch token', 'repo token'))
 
2045
        client.add_expected_call(
 
2046
            'Branch.get_config_file', ('memory:///', ),
 
2047
            'success', ('ok', ), "# line 1\n")
 
2048
        client.add_expected_call(
 
2049
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2050
            'repo token'),
 
2051
            'success', ('ok',))
 
2052
        client.add_expected_call(
 
2053
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2054
            'success', ('ok',))
 
2055
        transport = MemoryTransport()
 
2056
        branch = self.make_remote_branch(transport, client)
 
2057
        branch.lock_write()
 
2058
        config = branch.get_config_stack()
 
2059
        config.set('email', 'The Dude <lebowski@example.com>')
 
2060
        branch.unlock()
 
2061
        self.assertFinished(client)
 
2062
        self.assertEqual(
 
2063
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2064
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2065
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2066
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2067
                 ('memory:///', 'branch token', 'repo token'),
 
2068
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2069
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2070
            client._calls)
 
2071
 
1667
2072
 
1668
2073
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2074
 
1683
2088
        self.assertFinished(client)
1684
2089
 
1685
2090
 
 
2091
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2092
 
 
2093
    def test_simple(self):
 
2094
        transport = MemoryTransport()
 
2095
        client = FakeClient(transport.base)
 
2096
        client.add_expected_call(
 
2097
            'Branch.get_stacked_on_url', ('quack/',),
 
2098
            'error', ('NotStacked',),)
 
2099
        client.add_expected_call(
 
2100
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2101
            'success', ('ok', '0',),)
 
2102
        client.add_expected_call(
 
2103
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2104
            'error', ('NoSuchRevision', 'unknown',),)
 
2105
        transport.mkdir('quack')
 
2106
        transport = transport.clone('quack')
 
2107
        branch = self.make_remote_branch(transport, client)
 
2108
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2109
        self.assertRaises(errors.NoSuchRevision,
 
2110
            branch.revision_id_to_revno, 'unknown')
 
2111
        self.assertFinished(client)
 
2112
 
 
2113
    def test_dotted(self):
 
2114
        transport = MemoryTransport()
 
2115
        client = FakeClient(transport.base)
 
2116
        client.add_expected_call(
 
2117
            'Branch.get_stacked_on_url', ('quack/',),
 
2118
            'error', ('NotStacked',),)
 
2119
        client.add_expected_call(
 
2120
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2121
            'success', ('ok', '0',),)
 
2122
        client.add_expected_call(
 
2123
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2124
            'error', ('NoSuchRevision', 'unknown',),)
 
2125
        transport.mkdir('quack')
 
2126
        transport = transport.clone('quack')
 
2127
        branch = self.make_remote_branch(transport, client)
 
2128
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2129
        self.assertRaises(errors.NoSuchRevision,
 
2130
            branch.revision_id_to_dotted_revno, 'unknown')
 
2131
        self.assertFinished(client)
 
2132
 
 
2133
    def test_dotted_no_smart_verb(self):
 
2134
        self.setup_smart_server_with_call_log()
 
2135
        branch = self.make_branch('.')
 
2136
        self.disable_verb('Branch.revision_id_to_revno')
 
2137
        self.reset_smart_call_log()
 
2138
        self.assertEquals((0, ),
 
2139
            branch.revision_id_to_dotted_revno('null:'))
 
2140
        self.assertLength(7, self.hpss_calls)
 
2141
 
 
2142
 
1686
2143
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2144
 
1688
2145
    def test__get_config(self):
1805
2262
        client = FakeClient(transport.base)
1806
2263
        transport = transport.clone(transport_path)
1807
2264
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2265
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2266
            _client=False)
1810
2267
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2268
        return repo, client
1819
2276
 
1820
2277
    def test_get_format_description(self):
1821
2278
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2279
        real_format = branch.format_registry.get_default()
1823
2280
        remote_format._network_name = real_format.network_name()
1824
2281
        self.assertEqual(remoted_description(real_format),
1825
2282
            remote_format.get_format_description())
1828
2285
class TestRepositoryFormat(TestRemoteRepository):
1829
2286
 
1830
2287
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2288
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2289
        true_format = RemoteRepositoryFormat()
1833
2290
        true_format._network_name = true_name
1834
2291
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2292
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2293
        false_format = RemoteRepositoryFormat()
1837
2294
        false_format._network_name = false_name
1838
2295
        self.assertEqual(False, false_format.fast_deltas)
1839
2296
 
1840
2297
    def test_get_format_description(self):
1841
2298
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2299
        real_format = repository.format_registry.get_default()
1843
2300
        remote_repo_format._network_name = real_format.network_name()
1844
2301
        self.assertEqual(remoted_description(real_format),
1845
2302
            remote_repo_format.get_format_description())
1846
2303
 
1847
2304
 
 
2305
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2306
 
 
2307
    def test_empty(self):
 
2308
        transport_path = 'quack'
 
2309
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2310
        client.add_success_response_with_body('', 'ok')
 
2311
        self.assertEquals([], repo.all_revision_ids())
 
2312
        self.assertEqual(
 
2313
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2314
             ('quack/',))],
 
2315
            client._calls)
 
2316
 
 
2317
    def test_with_some_content(self):
 
2318
        transport_path = 'quack'
 
2319
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2320
        client.add_success_response_with_body(
 
2321
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2322
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2323
            repo.all_revision_ids())
 
2324
        self.assertEqual(
 
2325
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2326
             ('quack/',))],
 
2327
            client._calls)
 
2328
 
 
2329
 
1848
2330
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2331
 
1850
2332
    def test_revid_none(self):
1903
2385
                         result)
1904
2386
 
1905
2387
 
 
2388
class TestRepositoryBreakLock(TestRemoteRepository):
 
2389
 
 
2390
    def test_break_lock(self):
 
2391
        transport_path = 'quack'
 
2392
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2393
        client.add_success_response('ok')
 
2394
        repo.break_lock()
 
2395
        self.assertEqual(
 
2396
            [('call', 'Repository.break_lock', ('quack/',))],
 
2397
            client._calls)
 
2398
 
 
2399
 
 
2400
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2401
 
 
2402
    def test_get_serializer_format(self):
 
2403
        transport_path = 'hill'
 
2404
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2405
        client.add_success_response('ok', '7')
 
2406
        self.assertEquals('7', repo.get_serializer_format())
 
2407
        self.assertEqual(
 
2408
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2409
              ('hill/', ))],
 
2410
            client._calls)
 
2411
 
 
2412
 
 
2413
class TestRepositoryReconcile(TestRemoteRepository):
 
2414
 
 
2415
    def test_reconcile(self):
 
2416
        transport_path = 'hill'
 
2417
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2418
        body = ("garbage_inventories: 2\n"
 
2419
                "inconsistent_parents: 3\n")
 
2420
        client.add_expected_call(
 
2421
            'Repository.lock_write', ('hill/', ''),
 
2422
            'success', ('ok', 'a token'))
 
2423
        client.add_success_response_with_body(body, 'ok')
 
2424
        reconciler = repo.reconcile()
 
2425
        self.assertEqual(
 
2426
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2427
             ('call_expecting_body', 'Repository.reconcile',
 
2428
                ('hill/', 'a token'))],
 
2429
            client._calls)
 
2430
        self.assertEquals(2, reconciler.garbage_inventories)
 
2431
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2432
 
 
2433
 
 
2434
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2435
 
 
2436
    def test_text(self):
 
2437
        # ('ok',), body with signature text
 
2438
        transport_path = 'quack'
 
2439
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2440
        client.add_success_response_with_body(
 
2441
            'THETEXT', 'ok')
 
2442
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2443
        self.assertEqual(
 
2444
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2445
             ('quack/', 'revid'))],
 
2446
            client._calls)
 
2447
 
 
2448
    def test_no_signature(self):
 
2449
        transport_path = 'quick'
 
2450
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2451
        client.add_error_response('nosuchrevision', 'unknown')
 
2452
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2453
                "unknown")
 
2454
        self.assertEqual(
 
2455
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2456
              ('quick/', 'unknown'))],
 
2457
            client._calls)
 
2458
 
 
2459
 
1906
2460
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2461
 
1908
2462
    def test_get_graph(self):
1913
2467
        self.assertNotEqual(graph._parents_provider, repo)
1914
2468
 
1915
2469
 
 
2470
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2471
 
 
2472
    def test_add_signature_text(self):
 
2473
        transport_path = 'quack'
 
2474
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2475
        client.add_expected_call(
 
2476
            'Repository.lock_write', ('quack/', ''),
 
2477
            'success', ('ok', 'a token'))
 
2478
        client.add_expected_call(
 
2479
            'Repository.start_write_group', ('quack/', 'a token'),
 
2480
            'success', ('ok', ('token1', )))
 
2481
        client.add_expected_call(
 
2482
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2483
                'token1'),
 
2484
            'success', ('ok', ), None)
 
2485
        repo.lock_write()
 
2486
        repo.start_write_group()
 
2487
        self.assertIs(None,
 
2488
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2489
        self.assertEqual(
 
2490
            ('call_with_body_bytes_expecting_body',
 
2491
              'Repository.add_signature_text',
 
2492
                ('quack/', 'a token', 'rev1', 'token1'),
 
2493
              'every bloody emperor'),
 
2494
            client._calls[-1])
 
2495
 
 
2496
 
1916
2497
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2498
 
1918
2499
    def test_get_parent_map_caching(self):
1968
2549
        parents = repo.get_parent_map([rev_id])
1969
2550
        self.assertEqual(
1970
2551
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2552
              'Repository.get_parent_map',
 
2553
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2554
             ('disconnect medium',),
1974
2555
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2556
              ('quack/', ''))],
2095
2676
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2677
        self.assertLength(0, self.hpss_calls)
2097
2678
 
 
2679
    def test_exposes_get_cached_parent_map(self):
 
2680
        """RemoteRepository exposes get_cached_parent_map from
 
2681
        _unstacked_provider
 
2682
        """
 
2683
        r1 = u'\u0e33'.encode('utf8')
 
2684
        r2 = u'\u0dab'.encode('utf8')
 
2685
        lines = [' '.join([r2, r1]), r1]
 
2686
        encoded_body = bz2.compress('\n'.join(lines))
 
2687
 
 
2688
        transport_path = 'quack'
 
2689
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2690
        client.add_success_response_with_body(encoded_body, 'ok')
 
2691
        repo.lock_read()
 
2692
        # get_cached_parent_map should *not* trigger an RPC
 
2693
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2694
        self.assertEqual([], client._calls)
 
2695
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2696
        self.assertEqual({r1: (NULL_REVISION,)},
 
2697
            repo.get_cached_parent_map([r1]))
 
2698
        self.assertEqual(
 
2699
            [('call_with_body_bytes_expecting_body',
 
2700
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2701
              '\n\n0')],
 
2702
            client._calls)
 
2703
        repo.unlock()
 
2704
 
2098
2705
 
2099
2706
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2707
 
2115
2722
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2723
 
2117
2724
 
 
2725
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2726
 
 
2727
    def test_hpss_missing_revision(self):
 
2728
        transport_path = 'quack'
 
2729
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2730
        client.add_success_response_with_body(
 
2731
            '', 'ok', '10')
 
2732
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2733
            ['somerev1', 'anotherrev2'])
 
2734
        self.assertEqual(
 
2735
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2736
             ('quack/', ), "somerev1\nanotherrev2")],
 
2737
            client._calls)
 
2738
 
 
2739
    def test_hpss_get_single_revision(self):
 
2740
        transport_path = 'quack'
 
2741
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2742
        somerev1 = Revision("somerev1")
 
2743
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2744
        somerev1.timestamp = 1321828927
 
2745
        somerev1.timezone = -60
 
2746
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2747
        somerev1.message = "Message"
 
2748
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2749
            somerev1))
 
2750
        # Split up body into two bits to make sure the zlib compression object
 
2751
        # gets data fed twice.
 
2752
        client.add_success_response_with_body(
 
2753
                [body[:10], body[10:]], 'ok', '10')
 
2754
        revs = repo.get_revisions(['somerev1'])
 
2755
        self.assertEquals(revs, [somerev1])
 
2756
        self.assertEqual(
 
2757
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2758
             ('quack/', ), "somerev1")],
 
2759
            client._calls)
 
2760
 
 
2761
 
2118
2762
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2763
 
2120
2764
    def test_null_revision(self):
2257
2901
        self.setup_smart_server_with_call_log()
2258
2902
        tree = self.make_branch_and_memory_tree('.')
2259
2903
        tree.lock_write()
 
2904
        tree.add('')
2260
2905
        rev1 = tree.commit('First')
2261
2906
        rev2 = tree.commit('Second')
2262
2907
        tree.unlock()
2270
2915
                              call.call.method == verb])
2271
2916
 
2272
2917
 
 
2918
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2919
 
 
2920
    def test_has_signature_for_revision_id(self):
 
2921
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2922
        transport_path = 'quack'
 
2923
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2924
        client.add_success_response('yes')
 
2925
        result = repo.has_signature_for_revision_id('A')
 
2926
        self.assertEqual(
 
2927
            [('call', 'Repository.has_signature_for_revision_id',
 
2928
              ('quack/', 'A'))],
 
2929
            client._calls)
 
2930
        self.assertEqual(True, result)
 
2931
 
 
2932
    def test_is_not_shared(self):
 
2933
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2934
        transport_path = 'qwack'
 
2935
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2936
        client.add_success_response('no')
 
2937
        result = repo.has_signature_for_revision_id('A')
 
2938
        self.assertEqual(
 
2939
            [('call', 'Repository.has_signature_for_revision_id',
 
2940
              ('qwack/', 'A'))],
 
2941
            client._calls)
 
2942
        self.assertEqual(False, result)
 
2943
 
 
2944
 
 
2945
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2946
 
 
2947
    def test_get_physical_lock_status_yes(self):
 
2948
        transport_path = 'qwack'
 
2949
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2950
        client.add_success_response('yes')
 
2951
        result = repo.get_physical_lock_status()
 
2952
        self.assertEqual(
 
2953
            [('call', 'Repository.get_physical_lock_status',
 
2954
              ('qwack/', ))],
 
2955
            client._calls)
 
2956
        self.assertEqual(True, result)
 
2957
 
 
2958
    def test_get_physical_lock_status_no(self):
 
2959
        transport_path = 'qwack'
 
2960
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2961
        client.add_success_response('no')
 
2962
        result = repo.get_physical_lock_status()
 
2963
        self.assertEqual(
 
2964
            [('call', 'Repository.get_physical_lock_status',
 
2965
              ('qwack/', ))],
 
2966
            client._calls)
 
2967
        self.assertEqual(False, result)
 
2968
 
 
2969
 
2273
2970
class TestRepositoryIsShared(TestRemoteRepository):
2274
2971
 
2275
2972
    def test_is_shared(self):
2295
2992
        self.assertEqual(False, result)
2296
2993
 
2297
2994
 
 
2995
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
2996
 
 
2997
    def test_make_working_trees(self):
 
2998
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
2999
        transport_path = 'quack'
 
3000
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3001
        client.add_success_response('yes')
 
3002
        result = repo.make_working_trees()
 
3003
        self.assertEqual(
 
3004
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3005
            client._calls)
 
3006
        self.assertEqual(True, result)
 
3007
 
 
3008
    def test_no_working_trees(self):
 
3009
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3010
        transport_path = 'qwack'
 
3011
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3012
        client.add_success_response('no')
 
3013
        result = repo.make_working_trees()
 
3014
        self.assertEqual(
 
3015
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3016
            client._calls)
 
3017
        self.assertEqual(False, result)
 
3018
 
 
3019
 
2298
3020
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3021
 
2300
3022
    def test_lock_write(self):
2301
3023
        transport_path = 'quack'
2302
3024
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3025
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3026
        token = repo.lock_write().repository_token
2305
3027
        self.assertEqual(
2306
3028
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3029
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3030
        self.assertEqual('a token', token)
2309
3031
 
2310
3032
    def test_lock_write_already_locked(self):
2311
3033
        transport_path = 'quack'
2326
3048
            client._calls)
2327
3049
 
2328
3050
 
 
3051
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3052
 
 
3053
    def test_start_write_group(self):
 
3054
        transport_path = 'quack'
 
3055
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3056
        client.add_expected_call(
 
3057
            'Repository.lock_write', ('quack/', ''),
 
3058
            'success', ('ok', 'a token'))
 
3059
        client.add_expected_call(
 
3060
            'Repository.start_write_group', ('quack/', 'a token'),
 
3061
            'success', ('ok', ('token1', )))
 
3062
        repo.lock_write()
 
3063
        repo.start_write_group()
 
3064
 
 
3065
    def test_start_write_group_unsuspendable(self):
 
3066
        # Some repositories do not support suspending write
 
3067
        # groups. For those, fall back to the "real" repository.
 
3068
        transport_path = 'quack'
 
3069
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3070
        def stub_ensure_real():
 
3071
            client._calls.append(('_ensure_real',))
 
3072
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3073
        repo._ensure_real = stub_ensure_real
 
3074
        client.add_expected_call(
 
3075
            'Repository.lock_write', ('quack/', ''),
 
3076
            'success', ('ok', 'a token'))
 
3077
        client.add_expected_call(
 
3078
            'Repository.start_write_group', ('quack/', 'a token'),
 
3079
            'error', ('UnsuspendableWriteGroup',))
 
3080
        repo.lock_write()
 
3081
        repo.start_write_group()
 
3082
        self.assertEquals(client._calls[-2:], [ 
 
3083
            ('_ensure_real',),
 
3084
            ('start_write_group',)])
 
3085
 
 
3086
    def test_commit_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.start_write_group', ('quack/', 'a token'),
 
3094
            'success', ('ok', ['token1']))
 
3095
        client.add_expected_call(
 
3096
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3097
            'success', ('ok',))
 
3098
        repo.lock_write()
 
3099
        repo.start_write_group()
 
3100
        repo.commit_write_group()
 
3101
 
 
3102
    def test_abort_write_group(self):
 
3103
        transport_path = 'quack'
 
3104
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3105
        client.add_expected_call(
 
3106
            'Repository.lock_write', ('quack/', ''),
 
3107
            'success', ('ok', 'a token'))
 
3108
        client.add_expected_call(
 
3109
            'Repository.start_write_group', ('quack/', 'a token'),
 
3110
            'success', ('ok', ['token1']))
 
3111
        client.add_expected_call(
 
3112
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3113
            'success', ('ok',))
 
3114
        repo.lock_write()
 
3115
        repo.start_write_group()
 
3116
        repo.abort_write_group(False)
 
3117
 
 
3118
    def test_suspend_write_group(self):
 
3119
        transport_path = 'quack'
 
3120
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3121
        self.assertEquals([], repo.suspend_write_group())
 
3122
 
 
3123
    def test_resume_write_group(self):
 
3124
        transport_path = 'quack'
 
3125
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3126
        client.add_expected_call(
 
3127
            'Repository.lock_write', ('quack/', ''),
 
3128
            'success', ('ok', 'a token'))
 
3129
        client.add_expected_call(
 
3130
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3131
            'success', ('ok',))
 
3132
        repo.lock_write()
 
3133
        repo.resume_write_group(['token1'])
 
3134
 
 
3135
 
2329
3136
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3137
 
2331
3138
    def test_backwards_compat(self):
2390
3197
        self.assertEqual([], client._calls)
2391
3198
 
2392
3199
 
 
3200
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3201
    """Test Repository.iter_file_bytes."""
 
3202
 
 
3203
    def test_single(self):
 
3204
        transport_path = 'quack'
 
3205
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3206
        client.add_expected_call(
 
3207
            'Repository.iter_files_bytes', ('quack/', ),
 
3208
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3209
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3210
                "somerev", "myid")]):
 
3211
            self.assertEquals("myid", identifier)
 
3212
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3213
 
 
3214
    def test_missing(self):
 
3215
        transport_path = 'quack'
 
3216
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3217
        client.add_expected_call(
 
3218
            'Repository.iter_files_bytes',
 
3219
                ('quack/', ),
 
3220
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3221
            iter(["absent\0somefile\0somerev\n"]))
 
3222
        self.assertRaises(errors.RevisionNotPresent, list,
 
3223
                repo.iter_files_bytes(
 
3224
                [("somefile", "somerev", "myid")]))
 
3225
 
 
3226
 
2393
3227
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3228
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3229
    tests.
2402
3236
        the client is finished.
2403
3237
        """
2404
3238
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3239
        fmt = repository.format_registry.get_default()
2406
3240
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3241
        self.assertEqual([], resume_tokens)
2408
3242
        self.assertEqual(set(), missing_keys)
2508
3342
                return True
2509
3343
        repo._real_repository = FakeRealRepository()
2510
3344
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3345
        fmt = repository.format_registry.get_default()
2512
3346
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3347
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3348
        # Every record from the first inventory delta should have been sent to
2670
3504
        self.calls = calls
2671
3505
        self._pack_collection = _StubPackCollection(calls)
2672
3506
 
 
3507
    def start_write_group(self):
 
3508
        self.calls.append(('start_write_group',))
 
3509
 
2673
3510
    def is_in_write_group(self):
2674
3511
        return False
2675
3512
 
2734
3571
             ('pack collection autopack',)],
2735
3572
            client._calls)
2736
3573
 
 
3574
    def test_oom_error_reporting(self):
 
3575
        """An out-of-memory condition on the server is reported clearly"""
 
3576
        transport_path = 'quack'
 
3577
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3578
        client.add_expected_call(
 
3579
            'PackRepository.autopack', ('quack/',),
 
3580
            'error', ('MemoryError',))
 
3581
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3582
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3583
 
2737
3584
 
2738
3585
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3586
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3659
            detail='extra detail')
2813
3660
        self.assertEqual(expected_error, translated_error)
2814
3661
 
 
3662
    def test_norepository(self):
 
3663
        bzrdir = self.make_bzrdir('')
 
3664
        translated_error = self.translateTuple(('norepository',),
 
3665
            bzrdir=bzrdir)
 
3666
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3667
        self.assertEqual(expected_error, translated_error)
 
3668
 
2815
3669
    def test_LockContention(self):
2816
3670
        translated_error = self.translateTuple(('LockContention',))
2817
3671
        expected_error = errors.LockContention('(remote lock)')
2845
3699
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3700
        self.assertEqual(expected_error, translated_error)
2847
3701
 
 
3702
    def test_NotStacked(self):
 
3703
        branch = self.make_branch('')
 
3704
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3705
        expected_error = errors.NotStacked(branch)
 
3706
        self.assertEqual(expected_error, translated_error)
 
3707
 
2848
3708
    def test_ReadError_no_args(self):
2849
3709
        path = 'a path'
2850
3710
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3726
 
2867
3727
    def test_PermissionDenied_no_args(self):
2868
3728
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3729
        translated_error = self.translateTuple(('PermissionDenied',),
 
3730
            path=path)
2870
3731
        expected_error = errors.PermissionDenied(path)
2871
3732
        self.assertEqual(expected_error, translated_error)
2872
3733
 
2895
3756
        expected_error = errors.PermissionDenied(path, extra)
2896
3757
        self.assertEqual(expected_error, translated_error)
2897
3758
 
 
3759
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3760
 
 
3761
    def test_NoSuchFile_context_path(self):
 
3762
        local_path = "local path"
 
3763
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3764
            path=local_path)
 
3765
        expected_error = errors.ReadError(local_path)
 
3766
        self.assertEqual(expected_error, translated_error)
 
3767
 
 
3768
    def test_NoSuchFile_without_context(self):
 
3769
        remote_path = "remote path"
 
3770
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3771
        expected_error = errors.ReadError(remote_path)
 
3772
        self.assertEqual(expected_error, translated_error)
 
3773
 
 
3774
    def test_ReadOnlyError(self):
 
3775
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3776
        expected_error = errors.TransportNotPossible("readonly transport")
 
3777
        self.assertEqual(expected_error, translated_error)
 
3778
 
 
3779
    def test_MemoryError(self):
 
3780
        translated_error = self.translateTuple(('MemoryError',))
 
3781
        self.assertStartsWith(str(translated_error),
 
3782
            "remote server out of memory")
 
3783
 
 
3784
    def test_generic_IndexError_no_classname(self):
 
3785
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3786
        translated_error = self.translateErrorFromSmartServer(err)
 
3787
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3788
        self.assertEqual(expected_error, translated_error)
 
3789
 
 
3790
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3791
 
 
3792
    def test_generic_KeyError(self):
 
3793
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3794
        translated_error = self.translateErrorFromSmartServer(err)
 
3795
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3796
        self.assertEqual(expected_error, translated_error)
 
3797
 
2898
3798
 
2899
3799
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3800
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3945
        _, stacked = branch_factory()
3046
3946
        source = stacked.repository._get_source(target_repository_format)
3047
3947
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3948
        stacked.repository._ensure_real()
 
3949
        graph = stacked.repository.get_graph()
 
3950
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3951
                if r != NULL_REVISION]
 
3952
        revs.reverse()
 
3953
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3954
        self.reset_smart_call_log()
3051
3955
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3956
        # We trust that if a revision is in the stream the rest of the new
3055
3957
        # content for it is too, as per our main fetch tests; here we are
3056
3958
        # checking that the revisions are actually included at all, and their
3095
3997
        self.assertEqual(expected_revs, rev_ord)
3096
3998
        # Getting topological sort requires VFS calls still - one of which is
3097
3999
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4000
        self.assertLength(14, self.hpss_calls)
3099
4001
 
3100
4002
    def test_stacked_get_stream_groupcompress(self):
3101
4003
        # Repository._get_source.get_stream() from a stacked repository with
3142
4044
 
3143
4045
    def test_copy_content_into_avoids_revision_history(self):
3144
4046
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4047
        builder = self.make_branch_builder('remote')
 
4048
        builder.build_commit(message="Commit.")
3147
4049
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4050
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4051
        local.repository.fetch(remote_branch.repository)
3150
4052
        self.hpss_calls = []
3151
4053
        remote_branch.copy_content_into(local)
3152
4054
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4055
 
 
4056
    def test_fetch_everything_needs_just_one_call(self):
 
4057
        local = self.make_branch('local')
 
4058
        builder = self.make_branch_builder('remote')
 
4059
        builder.build_commit(message="Commit.")
 
4060
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4061
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4062
        self.hpss_calls = []
 
4063
        local.repository.fetch(
 
4064
            remote_branch.repository,
 
4065
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4066
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4067
 
 
4068
    def override_verb(self, verb_name, verb):
 
4069
        request_handlers = request.request_handlers
 
4070
        orig_verb = request_handlers.get(verb_name)
 
4071
        orig_info = request_handlers.get_info(verb_name)
 
4072
        request_handlers.register(verb_name, verb, override_existing=True)
 
4073
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4074
                override_existing=True, info=orig_info)
 
4075
 
 
4076
    def test_fetch_everything_backwards_compat(self):
 
4077
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4078
        
 
4079
        Pre-2.4 do not support 'everything' searches with the
 
4080
        Repository.get_stream_1.19 verb.
 
4081
        """
 
4082
        verb_log = []
 
4083
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4084
            """A version of the Repository.get_stream_1.19 verb patched to
 
4085
            reject 'everything' searches the way 2.3 and earlier do.
 
4086
            """
 
4087
            def recreate_search(self, repository, search_bytes,
 
4088
                                discard_excess=False):
 
4089
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4090
                if search_bytes == 'everything':
 
4091
                    return (None,
 
4092
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4093
                return super(OldGetStreamVerb,
 
4094
                        self).recreate_search(repository, search_bytes,
 
4095
                            discard_excess=discard_excess)
 
4096
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4097
        local = self.make_branch('local')
 
4098
        builder = self.make_branch_builder('remote')
 
4099
        builder.build_commit(message="Commit.")
 
4100
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4101
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4102
        self.hpss_calls = []
 
4103
        local.repository.fetch(
 
4104
            remote_branch.repository,
 
4105
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4106
        # make sure the overridden verb was used
 
4107
        self.assertLength(1, verb_log)
 
4108
        # more than one HPSS call is needed, but because it's a VFS callback
 
4109
        # its hard to predict exactly how many.
 
4110
        self.assertTrue(len(self.hpss_calls) > 1)
 
4111
 
 
4112
 
 
4113
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4114
    tests.TestCaseWithTransport):
 
4115
    """Ensure correct handling of bound_location modifications.
 
4116
 
 
4117
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4118
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4119
    happen in this context.
 
4120
    """
 
4121
 
 
4122
    def setUp(self):
 
4123
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4124
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4125
 
 
4126
    def make_master_and_checkout(self, master_name, checkout_name):
 
4127
        # Create the master branch and its associated checkout
 
4128
        self.master = self.make_branch_and_tree(master_name)
 
4129
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4130
        # Modify the master branch so there is something to update
 
4131
        self.master.commit('add stuff')
 
4132
        self.last_revid = self.master.commit('even more stuff')
 
4133
        self.bound_location = self.checkout.branch.get_bound_location()
 
4134
 
 
4135
    def assertUpdateSucceeds(self, new_location):
 
4136
        self.checkout.branch.set_bound_location(new_location)
 
4137
        self.checkout.update()
 
4138
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4139
 
 
4140
    def test_without_final_slash(self):
 
4141
        self.make_master_and_checkout('master', 'checkout')
 
4142
        # For unclear reasons some users have a bound_location without a final
 
4143
        # '/', simulate that by forcing such a value
 
4144
        self.assertEndsWith(self.bound_location, '/')
 
4145
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4146
 
 
4147
    def test_plus_sign(self):
 
4148
        self.make_master_and_checkout('+master', 'checkout')
 
4149
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4150
 
 
4151
    def test_tilda(self):
 
4152
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4153
        # interpretation
 
4154
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4155
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4156
 
 
4157
 
 
4158
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4159
 
 
4160
    def test_no_context(self):
 
4161
        class OutOfCoffee(errors.BzrError):
 
4162
            """A dummy exception for testing."""
 
4163
 
 
4164
            def __init__(self, urgency):
 
4165
                self.urgency = urgency
 
4166
        remote.no_context_error_translators.register("OutOfCoffee",
 
4167
            lambda err: OutOfCoffee(err.error_args[0]))
 
4168
        transport = MemoryTransport()
 
4169
        client = FakeClient(transport.base)
 
4170
        client.add_expected_call(
 
4171
            'Branch.get_stacked_on_url', ('quack/',),
 
4172
            'error', ('NotStacked',))
 
4173
        client.add_expected_call(
 
4174
            'Branch.last_revision_info',
 
4175
            ('quack/',),
 
4176
            'error', ('OutOfCoffee', 'low'))
 
4177
        transport.mkdir('quack')
 
4178
        transport = transport.clone('quack')
 
4179
        branch = self.make_remote_branch(transport, client)
 
4180
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4181
        self.assertFinished(client)
 
4182
 
 
4183
    def test_with_context(self):
 
4184
        class OutOfTea(errors.BzrError):
 
4185
            def __init__(self, branch, urgency):
 
4186
                self.branch = branch
 
4187
                self.urgency = urgency
 
4188
        remote.error_translators.register("OutOfTea",
 
4189
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4190
                find("branch")))
 
4191
        transport = MemoryTransport()
 
4192
        client = FakeClient(transport.base)
 
4193
        client.add_expected_call(
 
4194
            'Branch.get_stacked_on_url', ('quack/',),
 
4195
            'error', ('NotStacked',))
 
4196
        client.add_expected_call(
 
4197
            'Branch.last_revision_info',
 
4198
            ('quack/',),
 
4199
            'error', ('OutOfTea', 'low'))
 
4200
        transport.mkdir('quack')
 
4201
        transport = transport.clone('quack')
 
4202
        branch = self.make_remote_branch(transport, client)
 
4203
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4204
        self.assertFinished(client)
 
4205
 
 
4206
 
 
4207
class TestRepositoryPack(TestRemoteRepository):
 
4208
 
 
4209
    def test_pack(self):
 
4210
        transport_path = 'quack'
 
4211
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4212
        client.add_expected_call(
 
4213
            'Repository.lock_write', ('quack/', ''),
 
4214
            'success', ('ok', 'token'))
 
4215
        client.add_expected_call(
 
4216
            'Repository.pack', ('quack/', 'token', 'False'),
 
4217
            'success', ('ok',), )
 
4218
        client.add_expected_call(
 
4219
            'Repository.unlock', ('quack/', 'token'),
 
4220
            'success', ('ok', ))
 
4221
        repo.pack()
 
4222
 
 
4223
    def test_pack_with_hint(self):
 
4224
        transport_path = 'quack'
 
4225
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4226
        client.add_expected_call(
 
4227
            'Repository.lock_write', ('quack/', ''),
 
4228
            'success', ('ok', 'token'))
 
4229
        client.add_expected_call(
 
4230
            'Repository.pack', ('quack/', 'token', 'False'),
 
4231
            'success', ('ok',), )
 
4232
        client.add_expected_call(
 
4233
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4234
            'success', ('ok', ))
 
4235
        repo.pack(['hinta', 'hintb'])