~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 14:15:25 UTC
  • mto: (6471.1.4 iter-child-entries)
  • mto: This revision was merged to the branch mainline in revision 6472.
  • Revision ID: jelmer@samba.org-20120220141525-9azkfei62st8yc7w
Use inventories directly in fewer places.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2006-2012 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 (
 
31
    bencode,
30
32
    branch,
31
33
    bzrdir,
32
34
    config,
 
35
    controldir,
33
36
    errors,
34
 
    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
    _stream_to_byte_stream,
 
73
    )
 
74
from bzrlib.symbol_versioning import deprecated_in
60
75
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
76
    test_server,
65
77
    )
66
 
from bzrlib.transport import get_transport
 
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
79
from bzrlib.transport.memory import MemoryTransport
68
80
from bzrlib.transport.remote import (
69
81
    RemoteTransport,
70
82
    RemoteSSHTransport,
71
83
    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 = [
 
84
    )
 
85
 
 
86
 
 
87
load_tests = load_tests_apply_scenarios
 
88
 
 
89
 
 
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
91
 
 
92
    scenarios = [
78
93
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
94
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
95
        ('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):
 
96
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
97
 
86
98
 
87
99
    def setUp(self):
88
100
        super(BasicRemoteObjectTests, self).setUp()
89
101
        self.transport = self.get_transport()
90
102
        # make a branch that can be opened over the smart transport
91
103
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
104
        self.addCleanup(self.transport.disconnect)
96
105
 
97
106
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
107
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
108
        self.assertIsInstance(b, BzrDir)
100
109
 
101
110
    def test_open_remote_branch(self):
102
111
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
112
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
113
        branch = b.open_branch()
105
114
        self.assertIsInstance(branch, Branch)
106
115
 
114
123
 
115
124
    def test_remote_branch_revision_history(self):
116
125
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
 
126
        self.assertEqual([],
 
127
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
128
        r1 = self.local_wt.commit('1st commit')
119
129
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
 
130
        self.assertEqual([r1, r2],
 
131
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
121
132
 
122
133
    def test_find_correct_format(self):
123
134
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
135
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
136
        self.assertTrue(bzrdir.RemoteBzrProber
 
137
                        in controldir.ControlDirFormat._server_probers)
 
138
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
139
 
129
140
    def test_open_detected_smart_format(self):
130
141
        fmt = BzrDirFormat.find_format(self.transport)
164
175
    def test_remote_branch_set_append_revisions_only(self):
165
176
        # Make a format 1.9 branch, which supports append_revisions_only
166
177
        branch = self.make_branch('branch', format='1.9')
167
 
        config = branch.get_config()
168
178
        branch.set_append_revisions_only(True)
 
179
        config = branch.get_config_stack()
169
180
        self.assertEqual(
170
 
            'True', config.get_user_option('append_revisions_only'))
 
181
            True, config.get('append_revisions_only'))
171
182
        branch.set_append_revisions_only(False)
 
183
        config = branch.get_config_stack()
172
184
        self.assertEqual(
173
 
            'False', config.get_user_option('append_revisions_only'))
 
185
            False, config.get('append_revisions_only'))
174
186
 
175
187
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
176
188
        branch = self.make_branch('branch', format='knit')
177
 
        config = branch.get_config()
178
189
        self.assertRaises(
179
190
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
180
191
 
359
370
        a given client_base and transport_base.
360
371
        """
361
372
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
373
        t = transport.get_transport(transport_base)
 
374
        result = client_medium.remote_path_from_transport(t)
364
375
        self.assertEqual(expected, result)
365
376
 
366
377
    def test_remote_path_from_transport(self):
377
388
        a given transport_base and relpath of that transport.  (Note that
378
389
        HttpTransportBase is a subclass of SmartClientMedium)
379
390
        """
380
 
        base_transport = get_transport(transport_base)
 
391
        base_transport = transport.get_transport(transport_base)
381
392
        client_medium = base_transport.get_smart_medium()
382
393
        cloned_transport = base_transport.clone(relpath)
383
394
        result = client_medium.remote_path_from_transport(cloned_transport)
418
429
        # Calling _remember_remote_is_before again with a lower value works.
419
430
        client_medium._remember_remote_is_before((1, 5))
420
431
        self.assertTrue(client_medium._is_remote_before((1, 5)))
421
 
        # You cannot call _remember_remote_is_before with a larger value.
422
 
        self.assertRaises(
423
 
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
 
432
        # If you call _remember_remote_is_before with a higher value it logs a
 
433
        # warning, and continues to remember the lower value.
 
434
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
 
435
        client_medium._remember_remote_is_before((1, 9))
 
436
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
 
437
        self.assertTrue(client_medium._is_remote_before((1, 5)))
424
438
 
425
439
 
426
440
class TestBzrDirCloningMetaDir(TestRemote):
447
461
        client.add_expected_call(
448
462
            'BzrDir.open_branchV3', ('quack/',),
449
463
            'success', ('ref', self.get_url('referenced'))),
450
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
464
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
451
465
            _client=client)
452
466
        result = a_bzrdir.cloning_metadir()
453
467
        # We should have got a control dir matching the referenced branch.
466
480
        client.add_expected_call(
467
481
            'BzrDir.cloning_metadir', ('quack/', 'False'),
468
482
            'success', (control_name, '', ('branch', ''))),
469
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
483
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
470
484
            _client=client)
471
485
        result = a_bzrdir.cloning_metadir()
472
486
        # We should have got a reference control dir with default branch and
477
491
        self.assertEqual(None, result._branch_format)
478
492
        self.assertFinished(client)
479
493
 
 
494
    def test_unknown(self):
 
495
        transport = self.get_transport('quack')
 
496
        referenced = self.make_branch('referenced')
 
497
        expected = referenced.bzrdir.cloning_metadir()
 
498
        client = FakeClient(transport.base)
 
499
        client.add_expected_call(
 
500
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
501
            'success', ('unknown', 'unknown', ('branch', ''))),
 
502
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
503
            _client=client)
 
504
        self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
 
505
 
 
506
 
 
507
class TestBzrDirCheckoutMetaDir(TestRemote):
 
508
 
 
509
    def test__get_checkout_format(self):
 
510
        transport = MemoryTransport()
 
511
        client = FakeClient(transport.base)
 
512
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
513
        control_name = reference_bzrdir_format.network_name()
 
514
        client.add_expected_call(
 
515
            'BzrDir.checkout_metadir', ('quack/', ),
 
516
            'success', (control_name, '', ''))
 
517
        transport.mkdir('quack')
 
518
        transport = transport.clone('quack')
 
519
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
520
            _client=client)
 
521
        result = a_bzrdir.checkout_metadir()
 
522
        # We should have got a reference control dir with default branch and
 
523
        # repository formats.
 
524
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
525
        self.assertEqual(None, result._repository_format)
 
526
        self.assertEqual(None, result._branch_format)
 
527
        self.assertFinished(client)
 
528
 
 
529
    def test_unknown_format(self):
 
530
        transport = MemoryTransport()
 
531
        client = FakeClient(transport.base)
 
532
        client.add_expected_call(
 
533
            'BzrDir.checkout_metadir', ('quack/',),
 
534
            'success', ('dontknow', '', ''))
 
535
        transport.mkdir('quack')
 
536
        transport = transport.clone('quack')
 
537
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
538
            _client=client)
 
539
        self.assertRaises(errors.UnknownFormatError,
 
540
            a_bzrdir.checkout_metadir)
 
541
        self.assertFinished(client)
 
542
 
 
543
 
 
544
class TestBzrDirGetBranches(TestRemote):
 
545
 
 
546
    def test_get_branches(self):
 
547
        transport = MemoryTransport()
 
548
        client = FakeClient(transport.base)
 
549
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
550
        branch_name = reference_bzrdir_format.get_branch_format().network_name()
 
551
        client.add_success_response_with_body(
 
552
            bencode.bencode({
 
553
                "foo": ("branch", branch_name),
 
554
                "": ("branch", branch_name)}), "success")
 
555
        client.add_success_response(
 
556
            'ok', '', 'no', 'no', 'no',
 
557
                reference_bzrdir_format.repository_format.network_name())
 
558
        client.add_error_response('NotStacked')
 
559
        client.add_success_response(
 
560
            'ok', '', 'no', 'no', 'no',
 
561
                reference_bzrdir_format.repository_format.network_name())
 
562
        client.add_error_response('NotStacked')
 
563
        transport.mkdir('quack')
 
564
        transport = transport.clone('quack')
 
565
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
566
            _client=client)
 
567
        result = a_bzrdir.get_branches()
 
568
        self.assertEquals(set(["", "foo"]), set(result.keys()))
 
569
        self.assertEqual(
 
570
            [('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
 
571
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
572
             ('call', 'Branch.get_stacked_on_url', ('quack/', )),
 
573
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
574
             ('call', 'Branch.get_stacked_on_url', ('quack/', ))],
 
575
            client._calls)
 
576
 
 
577
 
 
578
class TestBzrDirDestroyBranch(TestRemote):
 
579
 
 
580
    def test_destroy_default(self):
 
581
        transport = self.get_transport('quack')
 
582
        referenced = self.make_branch('referenced')
 
583
        client = FakeClient(transport.base)
 
584
        client.add_expected_call(
 
585
            'BzrDir.destroy_branch', ('quack/', ),
 
586
            'success', ('ok',)),
 
587
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
588
            _client=client)
 
589
        a_bzrdir.destroy_branch()
 
590
        self.assertFinished(client)
 
591
 
 
592
 
 
593
class TestBzrDirHasWorkingTree(TestRemote):
 
594
 
 
595
    def test_has_workingtree(self):
 
596
        transport = self.get_transport('quack')
 
597
        client = FakeClient(transport.base)
 
598
        client.add_expected_call(
 
599
            'BzrDir.has_workingtree', ('quack/',),
 
600
            'success', ('yes',)),
 
601
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
602
            _client=client)
 
603
        self.assertTrue(a_bzrdir.has_workingtree())
 
604
        self.assertFinished(client)
 
605
 
 
606
    def test_no_workingtree(self):
 
607
        transport = self.get_transport('quack')
 
608
        client = FakeClient(transport.base)
 
609
        client.add_expected_call(
 
610
            'BzrDir.has_workingtree', ('quack/',),
 
611
            'success', ('no',)),
 
612
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
613
            _client=client)
 
614
        self.assertFalse(a_bzrdir.has_workingtree())
 
615
        self.assertFinished(client)
 
616
 
 
617
 
 
618
class TestBzrDirDestroyRepository(TestRemote):
 
619
 
 
620
    def test_destroy_repository(self):
 
621
        transport = self.get_transport('quack')
 
622
        client = FakeClient(transport.base)
 
623
        client.add_expected_call(
 
624
            'BzrDir.destroy_repository', ('quack/',),
 
625
            'success', ('ok',)),
 
626
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
627
            _client=client)
 
628
        a_bzrdir.destroy_repository()
 
629
        self.assertFinished(client)
 
630
 
480
631
 
481
632
class TestBzrDirOpen(TestRemote):
482
633
 
492
643
        client.add_expected_call(
493
644
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
494
645
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
495
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
646
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
496
647
        self.assertFinished(client)
497
648
 
498
649
    def test_present_without_workingtree(self):
499
650
        client, transport = self.make_fake_client_and_transport()
500
651
        client.add_expected_call(
501
652
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
502
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
653
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
503
654
            _client=client, _force_probe=True)
504
655
        self.assertIsInstance(bd, RemoteBzrDir)
505
656
        self.assertFalse(bd.has_workingtree())
510
661
        client, transport = self.make_fake_client_and_transport()
511
662
        client.add_expected_call(
512
663
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
513
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
664
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
514
665
            _client=client, _force_probe=True)
515
666
        self.assertIsInstance(bd, RemoteBzrDir)
516
667
        self.assertTrue(bd.has_workingtree())
523
674
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
524
675
        client.add_expected_call(
525
676
            'BzrDir.open', ('quack/',), 'success', ('yes',))
526
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
677
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
678
            _client=client, _force_probe=True)
 
679
        self.assertIsInstance(bd, RemoteBzrDir)
 
680
        self.assertFinished(client)
 
681
 
 
682
    def test_backwards_compat_hpss_v2(self):
 
683
        client, transport = self.make_fake_client_and_transport()
 
684
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
685
        # server: upon first RPC call detect the protocol version, and because
 
686
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
687
        # continuing with the RPC.
 
688
        orig_check_call = client._check_call
 
689
        def check_call(method, args):
 
690
            client._medium._protocol_version = 2
 
691
            client._medium._remember_remote_is_before((1, 6))
 
692
            client._check_call = orig_check_call
 
693
            client._check_call(method, args)
 
694
        client._check_call = check_call
 
695
        client.add_expected_call(
 
696
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
697
        client.add_expected_call(
 
698
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
699
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
527
700
            _client=client, _force_probe=True)
528
701
        self.assertIsInstance(bd, RemoteBzrDir)
529
702
        self.assertFinished(client)
560
733
        client.add_expected_call(
561
734
            'Branch.get_stacked_on_url', ('quack/',),
562
735
            'error', ('NotStacked',))
563
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
736
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
564
737
            _client=client)
565
738
        result = bzrdir.open_branch()
566
739
        self.assertIsInstance(result, RemoteBranch)
573
746
        transport = transport.clone('quack')
574
747
        client = FakeClient(transport.base)
575
748
        client.add_error_response('nobranch')
576
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
749
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
577
750
            _client=client)
578
751
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
579
752
        self.assertEqual(
584
757
        # _get_tree_branch is a form of open_branch, but it should only ask for
585
758
        # branch opening, not any other network requests.
586
759
        calls = []
587
 
        def open_branch():
 
760
        def open_branch(name=None, possible_transports=None):
588
761
            calls.append("Called")
589
762
            return "a-branch"
590
763
        transport = MemoryTransport()
591
764
        # no requests on the network - catches other api calls being made.
592
765
        client = FakeClient(transport.base)
593
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
766
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
594
767
            _client=client)
595
768
        # patch the open_branch call to record that it was called.
596
769
        bzrdir.open_branch = open_branch
615
788
        client.add_expected_call(
616
789
            'Branch.get_stacked_on_url', ('~hello/',),
617
790
            'error', ('NotStacked',))
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
791
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
792
            _client=client)
620
793
        result = bzrdir.open_branch()
621
794
        self.assertFinished(client)
638
811
        client.add_success_response(
639
812
            'ok', '', rich_response, subtree_response, external_lookup,
640
813
            network_name)
641
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
814
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
642
815
            _client=client)
643
816
        result = bzrdir.open_repository()
644
817
        self.assertEqual(
661
834
        old.
662
835
        """
663
836
        self.assertRaises(errors.NotBranchError,
664
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
837
            RemoteBzrProber.probe_transport, OldServerTransport())
665
838
 
666
839
 
667
840
class TestBzrDirCreateBranch(TestRemote):
690
863
            'BzrDir.create_branch', ('quack/', network_name),
691
864
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
692
865
            reference_repo_name))
693
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
866
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
694
867
            _client=client)
695
868
        branch = a_bzrdir.create_branch()
696
869
        # We should have got a remote branch
699
872
        format = branch._format
700
873
        self.assertEqual(network_name, format.network_name())
701
874
 
 
875
    def test_already_open_repo_and_reused_medium(self):
 
876
        """Bug 726584: create_branch(..., repository=repo) should work
 
877
        regardless of what the smart medium's base URL is.
 
878
        """
 
879
        self.transport_server = test_server.SmartTCPServer_for_testing
 
880
        transport = self.get_transport('.')
 
881
        repo = self.make_repository('quack')
 
882
        # Client's medium rooted a transport root (not at the bzrdir)
 
883
        client = FakeClient(transport.base)
 
884
        transport = transport.clone('quack')
 
885
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
886
        reference_format = reference_bzrdir_format.get_branch_format()
 
887
        network_name = reference_format.network_name()
 
888
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
889
        reference_repo_name = reference_repo_fmt.network_name()
 
890
        client.add_expected_call(
 
891
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
892
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
893
            reference_repo_name))
 
894
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
895
            _client=client)
 
896
        branch = a_bzrdir.create_branch(repository=repo)
 
897
        # We should have got a remote branch
 
898
        self.assertIsInstance(branch, remote.RemoteBranch)
 
899
        # its format should have the settings from the response
 
900
        format = branch._format
 
901
        self.assertEqual(network_name, format.network_name())
 
902
 
702
903
 
703
904
class TestBzrDirCreateRepository(TestRemote):
704
905
 
725
926
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
726
927
                'False'),
727
928
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
728
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
929
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
729
930
            _client=client)
730
931
        repo = a_bzrdir.create_repository()
731
932
        # We should have got a remote repository
754
955
        # name.
755
956
        client.add_success_response_with_body(
756
957
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
958
        client.add_success_response('stat', '0', '65535')
757
959
        client.add_success_response_with_body(
758
960
            reference_format.get_format_string(), 'ok')
759
961
        # PackRepository wants to do a stat
760
962
        client.add_success_response('stat', '0', '65535')
761
963
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
762
964
            _client=client)
763
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
965
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
764
966
            _client=client)
765
967
        repo = bzrdir.open_repository()
766
968
        self.assertEqual(
768
970
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
769
971
             ('call', 'BzrDir.find_repository', ('quack/',)),
770
972
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
973
             ('call', 'stat', ('/quack/.bzr',)),
771
974
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
772
975
             ('call', 'stat', ('/quack/.bzr/repository',)),
773
976
             ],
787
990
        # name.
788
991
        client.add_success_response_with_body(
789
992
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
993
        client.add_success_response('stat', '0', '65535')
790
994
        client.add_success_response_with_body(
791
995
            reference_format.get_format_string(), 'ok')
792
996
        # PackRepository wants to do a stat
793
997
        client.add_success_response('stat', '0', '65535')
794
998
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
795
999
            _client=client)
796
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
1000
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
797
1001
            _client=client)
798
1002
        repo = bzrdir.open_repository()
799
1003
        self.assertEqual(
800
1004
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
801
1005
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
802
1006
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
1007
             ('call', 'stat', ('/quack/.bzr',)),
803
1008
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
804
1009
             ('call', 'stat', ('/quack/.bzr/repository',)),
805
1010
             ],
814
1019
        transport = transport.clone('quack')
815
1020
        client = FakeClient(transport.base)
816
1021
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
817
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1022
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
818
1023
            _client=client)
819
1024
        repo = bzrdir.open_repository()
820
1025
        self.assertEqual(
827
1032
 
828
1033
    def test_success(self):
829
1034
        """Simple test for typical successful call."""
830
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1035
        fmt = RemoteBzrDirFormat()
831
1036
        default_format_name = BzrDirFormat.get_default_format().network_name()
832
1037
        transport = self.get_transport()
833
1038
        client = FakeClient(transport.base)
849
1054
        """Error responses are translated, e.g. 'PermissionDenied' raises the
850
1055
        corresponding error from the client.
851
1056
        """
852
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1057
        fmt = RemoteBzrDirFormat()
853
1058
        default_format_name = BzrDirFormat.get_default_format().network_name()
854
1059
        transport = self.get_transport()
855
1060
        client = FakeClient(transport.base)
873
1078
        """Integration test for error translation."""
874
1079
        transport = self.make_smart_server('foo')
875
1080
        transport = transport.clone('no-such-path')
876
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1081
        fmt = RemoteBzrDirFormat()
877
1082
        err = self.assertRaises(errors.NoSuchFile,
878
1083
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
879
1084
 
910
1115
 
911
1116
    def make_remote_bzrdir(self, transport, client):
912
1117
        """Make a RemotebzrDir using 'client' as the _client."""
913
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1118
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
914
1119
            _client=client)
915
1120
 
916
1121
 
942
1147
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
943
1148
 
944
1149
 
 
1150
class TestBranchBreakLock(RemoteBranchTestCase):
 
1151
 
 
1152
    def test_break_lock(self):
 
1153
        transport_path = 'quack'
 
1154
        transport = MemoryTransport()
 
1155
        client = FakeClient(transport.base)
 
1156
        client.add_expected_call(
 
1157
            'Branch.get_stacked_on_url', ('quack/',),
 
1158
            'error', ('NotStacked',))
 
1159
        client.add_expected_call(
 
1160
            'Branch.break_lock', ('quack/',),
 
1161
            'success', ('ok',))
 
1162
        transport.mkdir('quack')
 
1163
        transport = transport.clone('quack')
 
1164
        branch = self.make_remote_branch(transport, client)
 
1165
        branch.break_lock()
 
1166
        self.assertFinished(client)
 
1167
 
 
1168
 
 
1169
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1170
 
 
1171
    def test_get_physical_lock_status_yes(self):
 
1172
        transport = MemoryTransport()
 
1173
        client = FakeClient(transport.base)
 
1174
        client.add_expected_call(
 
1175
            'Branch.get_stacked_on_url', ('quack/',),
 
1176
            'error', ('NotStacked',))
 
1177
        client.add_expected_call(
 
1178
            'Branch.get_physical_lock_status', ('quack/',),
 
1179
            'success', ('yes',))
 
1180
        transport.mkdir('quack')
 
1181
        transport = transport.clone('quack')
 
1182
        branch = self.make_remote_branch(transport, client)
 
1183
        result = branch.get_physical_lock_status()
 
1184
        self.assertFinished(client)
 
1185
        self.assertEqual(True, result)
 
1186
 
 
1187
    def test_get_physical_lock_status_no(self):
 
1188
        transport = MemoryTransport()
 
1189
        client = FakeClient(transport.base)
 
1190
        client.add_expected_call(
 
1191
            'Branch.get_stacked_on_url', ('quack/',),
 
1192
            'error', ('NotStacked',))
 
1193
        client.add_expected_call(
 
1194
            'Branch.get_physical_lock_status', ('quack/',),
 
1195
            'success', ('no',))
 
1196
        transport.mkdir('quack')
 
1197
        transport = transport.clone('quack')
 
1198
        branch = self.make_remote_branch(transport, client)
 
1199
        result = branch.get_physical_lock_status()
 
1200
        self.assertFinished(client)
 
1201
        self.assertEqual(False, result)
 
1202
 
 
1203
 
945
1204
class TestBranchGetParent(RemoteBranchTestCase):
946
1205
 
947
1206
    def test_no_parent(self):
1037
1296
        verb = 'Branch.set_parent_location'
1038
1297
        self.disable_verb(verb)
1039
1298
        branch.set_parent('http://foo/')
1040
 
        self.assertLength(12, self.hpss_calls)
 
1299
        self.assertLength(14, self.hpss_calls)
1041
1300
 
1042
1301
 
1043
1302
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1118
1377
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1119
1378
 
1120
1379
 
 
1380
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1381
 
 
1382
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1383
        transport = MemoryTransport()
 
1384
        client = FakeClient(transport.base)
 
1385
        client.add_expected_call(
 
1386
            'Branch.get_stacked_on_url', ('quack/',),
 
1387
            'error', ('NotStacked',))
 
1388
        client.add_expected_call(
 
1389
            'Branch.last_revision_info', ('quack/',),
 
1390
            'success', ('ok', '1', 'rev-tip'))
 
1391
        client.add_expected_call(
 
1392
            'Branch.get_config_file', ('quack/',),
 
1393
            'success', ('ok',), '')
 
1394
        transport.mkdir('quack')
 
1395
        transport = transport.clone('quack')
 
1396
        branch = self.make_remote_branch(transport, client)
 
1397
        result = branch.heads_to_fetch()
 
1398
        self.assertFinished(client)
 
1399
        self.assertEqual((set(['rev-tip']), set()), result)
 
1400
 
 
1401
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1402
        transport = MemoryTransport()
 
1403
        client = FakeClient(transport.base)
 
1404
        client.add_expected_call(
 
1405
            'Branch.get_stacked_on_url', ('quack/',),
 
1406
            'error', ('NotStacked',))
 
1407
        client.add_expected_call(
 
1408
            'Branch.last_revision_info', ('quack/',),
 
1409
            'success', ('ok', '1', 'rev-tip'))
 
1410
        client.add_expected_call(
 
1411
            'Branch.get_config_file', ('quack/',),
 
1412
            'success', ('ok',), 'branch.fetch_tags = True')
 
1413
        # XXX: this will break if the default format's serialization of tags
 
1414
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1415
        client.add_expected_call(
 
1416
            'Branch.get_tags_bytes', ('quack/',),
 
1417
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1418
        transport.mkdir('quack')
 
1419
        transport = transport.clone('quack')
 
1420
        branch = self.make_remote_branch(transport, client)
 
1421
        result = branch.heads_to_fetch()
 
1422
        self.assertFinished(client)
 
1423
        self.assertEqual(
 
1424
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1425
 
 
1426
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1427
        transport = MemoryTransport()
 
1428
        client = FakeClient(transport.base)
 
1429
        client.add_expected_call(
 
1430
            'Branch.get_stacked_on_url', ('quack/',),
 
1431
            'error', ('NotStacked',))
 
1432
        client.add_expected_call(
 
1433
            'Branch.heads_to_fetch', ('quack/',),
 
1434
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1435
        transport.mkdir('quack')
 
1436
        transport = transport.clone('quack')
 
1437
        branch = self.make_remote_branch(transport, client)
 
1438
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1439
        result = branch.heads_to_fetch()
 
1440
        self.assertFinished(client)
 
1441
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1442
 
 
1443
    def make_branch_with_tags(self):
 
1444
        self.setup_smart_server_with_call_log()
 
1445
        # Make a branch with a single revision.
 
1446
        builder = self.make_branch_builder('foo')
 
1447
        builder.start_series()
 
1448
        builder.build_snapshot('tip', None, [
 
1449
            ('add', ('', 'root-id', 'directory', ''))])
 
1450
        builder.finish_series()
 
1451
        branch = builder.get_branch()
 
1452
        # Add two tags to that branch
 
1453
        branch.tags.set_tag('tag-1', 'rev-1')
 
1454
        branch.tags.set_tag('tag-2', 'rev-2')
 
1455
        return branch
 
1456
 
 
1457
    def test_backwards_compatible(self):
 
1458
        br = self.make_branch_with_tags()
 
1459
        br.get_config_stack().set('branch.fetch_tags', True)
 
1460
        self.addCleanup(br.lock_read().unlock)
 
1461
        # Disable the heads_to_fetch verb
 
1462
        verb = 'Branch.heads_to_fetch'
 
1463
        self.disable_verb(verb)
 
1464
        self.reset_smart_call_log()
 
1465
        result = br.heads_to_fetch()
 
1466
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1467
        self.assertEqual(
 
1468
            ['Branch.last_revision_info', 'Branch.get_tags_bytes'],
 
1469
            [call.call.method for call in self.hpss_calls])
 
1470
 
 
1471
    def test_backwards_compatible_no_tags(self):
 
1472
        br = self.make_branch_with_tags()
 
1473
        br.get_config_stack().set('branch.fetch_tags', False)
 
1474
        self.addCleanup(br.lock_read().unlock)
 
1475
        # Disable the heads_to_fetch verb
 
1476
        verb = 'Branch.heads_to_fetch'
 
1477
        self.disable_verb(verb)
 
1478
        self.reset_smart_call_log()
 
1479
        result = br.heads_to_fetch()
 
1480
        self.assertEqual((set(['tip']), set()), result)
 
1481
        self.assertEqual(
 
1482
            ['Branch.last_revision_info'],
 
1483
            [call.call.method for call in self.hpss_calls])
 
1484
 
 
1485
 
1121
1486
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1122
1487
 
1123
1488
    def test_empty_branch(self):
1178
1543
        client.add_expected_call(
1179
1544
            'Branch.get_stacked_on_url', ('stacked/',),
1180
1545
            'success', ('ok', vfs_url))
1181
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1546
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1182
1547
            _client=client)
1183
1548
        repo_fmt = remote.RemoteRepositoryFormat()
1184
1549
        repo_fmt._custom_format = stacked_branch.repository._format
1211
1576
        # this will also do vfs access, but that goes direct to the transport
1212
1577
        # and isn't seen by the FakeClient.
1213
1578
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1214
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1579
            RemoteBzrDirFormat(), _client=client)
1215
1580
        branch = bzrdir.open_branch()
1216
1581
        result = branch.get_stacked_on_url()
1217
1582
        self.assertEqual('../base', result)
1223
1588
            len(branch.repository._real_repository._fallback_repositories))
1224
1589
 
1225
1590
    def test_get_stacked_on_real_branch(self):
1226
 
        base_branch = self.make_branch('base', format='1.6')
1227
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1591
        base_branch = self.make_branch('base')
 
1592
        stacked_branch = self.make_branch('stacked')
1228
1593
        stacked_branch.set_stacked_on_url('../base')
1229
1594
        reference_format = self.get_repo_format()
1230
1595
        network_name = reference_format.network_name()
1235
1600
            'success', ('branch', branch_network_name))
1236
1601
        client.add_expected_call(
1237
1602
            'BzrDir.find_repositoryV3', ('stacked/',),
1238
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1603
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1239
1604
        # called twice, once from constructor and then again by us
1240
1605
        client.add_expected_call(
1241
1606
            'Branch.get_stacked_on_url', ('stacked/',),
1244
1609
            'Branch.get_stacked_on_url', ('stacked/',),
1245
1610
            'success', ('ok', '../base'))
1246
1611
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1247
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1612
            RemoteBzrDirFormat(), _client=client)
1248
1613
        branch = bzrdir.open_branch()
1249
1614
        result = branch.get_stacked_on_url()
1250
1615
        self.assertEqual('../base', result)
1258
1623
class TestBranchSetLastRevision(RemoteBranchTestCase):
1259
1624
 
1260
1625
    def test_set_empty(self):
1261
 
        # set_revision_history([]) is translated to calling
 
1626
        # _set_last_revision_info('null:') is translated to calling
1262
1627
        # Branch.set_last_revision(path, '') on the wire.
1263
1628
        transport = MemoryTransport()
1264
1629
        transport.mkdir('branch')
1282
1647
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1283
1648
            'success', ('ok',))
1284
1649
        branch = self.make_remote_branch(transport, client)
1285
 
        # This is a hack to work around the problem that RemoteBranch currently
1286
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1287
 
        branch._ensure_real = lambda: None
1288
1650
        branch.lock_write()
1289
 
        result = branch.set_revision_history([])
 
1651
        result = branch._set_last_revision(NULL_REVISION)
1290
1652
        branch.unlock()
1291
1653
        self.assertEqual(None, result)
1292
1654
        self.assertFinished(client)
1293
1655
 
1294
1656
    def test_set_nonempty(self):
1295
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1657
        # set_last_revision_info(N, rev-idN) is translated to calling
1296
1658
        # Branch.set_last_revision(path, rev-idN) on the wire.
1297
1659
        transport = MemoryTransport()
1298
1660
        transport.mkdir('branch')
1319
1681
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1320
1682
            'success', ('ok',))
1321
1683
        branch = self.make_remote_branch(transport, client)
1322
 
        # This is a hack to work around the problem that RemoteBranch currently
1323
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1324
 
        branch._ensure_real = lambda: None
1325
1684
        # Lock the branch, reset the record of remote calls.
1326
1685
        branch.lock_write()
1327
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1686
        result = branch._set_last_revision('rev-id2')
1328
1687
        branch.unlock()
1329
1688
        self.assertEqual(None, result)
1330
1689
        self.assertFinished(client)
1360
1719
        branch = self.make_remote_branch(transport, client)
1361
1720
        branch.lock_write()
1362
1721
        self.assertRaises(
1363
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1722
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1364
1723
        branch.unlock()
1365
1724
        self.assertFinished(client)
1366
1725
 
1394
1753
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1395
1754
            'success', ('ok',))
1396
1755
        branch = self.make_remote_branch(transport, client)
1397
 
        branch._ensure_real = lambda: None
1398
1756
        branch.lock_write()
1399
1757
        # The 'TipChangeRejected' error response triggered by calling
1400
 
        # set_revision_history causes a TipChangeRejected exception.
 
1758
        # set_last_revision_info causes a TipChangeRejected exception.
1401
1759
        err = self.assertRaises(
1402
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1760
            errors.TipChangeRejected,
 
1761
            branch._set_last_revision, 'rev-id')
1403
1762
        # The UTF-8 message from the response has been decoded into a unicode
1404
1763
        # object.
1405
1764
        self.assertIsInstance(err.msg, unicode)
1593
1952
    def test_get_multi_line_branch_conf(self):
1594
1953
        # Make sure that multiple-line branch.conf files are supported
1595
1954
        #
1596
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1955
        # https://bugs.launchpad.net/bzr/+bug/354075
1597
1956
        client = FakeClient()
1598
1957
        client.add_expected_call(
1599
1958
            'Branch.get_stacked_on_url', ('memory:///',),
1627
1986
        branch.unlock()
1628
1987
        self.assertFinished(client)
1629
1988
 
 
1989
    def test_set_option_with_dict(self):
 
1990
        client = FakeClient()
 
1991
        client.add_expected_call(
 
1992
            'Branch.get_stacked_on_url', ('memory:///',),
 
1993
            'error', ('NotStacked',),)
 
1994
        client.add_expected_call(
 
1995
            'Branch.lock_write', ('memory:///', '', ''),
 
1996
            'success', ('ok', 'branch token', 'repo token'))
 
1997
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1998
        client.add_expected_call(
 
1999
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
2000
            'repo token', encoded_dict_value, 'foo', ''),
 
2001
            'success', ())
 
2002
        client.add_expected_call(
 
2003
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2004
            'success', ('ok',))
 
2005
        transport = MemoryTransport()
 
2006
        branch = self.make_remote_branch(transport, client)
 
2007
        branch.lock_write()
 
2008
        config = branch._get_config()
 
2009
        config.set_option(
 
2010
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2011
            'foo')
 
2012
        branch.unlock()
 
2013
        self.assertFinished(client)
 
2014
 
1630
2015
    def test_backwards_compat_set_option(self):
1631
2016
        self.setup_smart_server_with_call_log()
1632
2017
        branch = self.make_branch('.')
1636
2021
        self.addCleanup(branch.unlock)
1637
2022
        self.reset_smart_call_log()
1638
2023
        branch._get_config().set_option('value', 'name')
1639
 
        self.assertLength(10, self.hpss_calls)
 
2024
        self.assertLength(11, self.hpss_calls)
1640
2025
        self.assertEqual('value', branch._get_config().get_option('name'))
1641
2026
 
 
2027
    def test_backwards_compat_set_option_with_dict(self):
 
2028
        self.setup_smart_server_with_call_log()
 
2029
        branch = self.make_branch('.')
 
2030
        verb = 'Branch.set_config_option_dict'
 
2031
        self.disable_verb(verb)
 
2032
        branch.lock_write()
 
2033
        self.addCleanup(branch.unlock)
 
2034
        self.reset_smart_call_log()
 
2035
        config = branch._get_config()
 
2036
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2037
        config.set_option(value_dict, 'name')
 
2038
        self.assertLength(11, self.hpss_calls)
 
2039
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2040
 
 
2041
 
 
2042
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2043
 
 
2044
    def test_get_branch_conf(self):
 
2045
        # in an empty branch we decode the response properly
 
2046
        client = FakeClient()
 
2047
        client.add_expected_call(
 
2048
            'Branch.get_stacked_on_url', ('memory:///',),
 
2049
            'error', ('NotStacked',),)
 
2050
        client.add_success_response_with_body('# config file body', 'ok')
 
2051
        transport = MemoryTransport()
 
2052
        branch = self.make_remote_branch(transport, client)
 
2053
        config = branch.get_config_stack()
 
2054
        config.get("email")
 
2055
        config.get("log_format")
 
2056
        self.assertEqual(
 
2057
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2058
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2059
            client._calls)
 
2060
 
 
2061
    def test_set_branch_conf(self):
 
2062
        client = FakeClient()
 
2063
        client.add_expected_call(
 
2064
            'Branch.get_stacked_on_url', ('memory:///',),
 
2065
            'error', ('NotStacked',),)
 
2066
        client.add_expected_call(
 
2067
            'Branch.lock_write', ('memory:///', '', ''),
 
2068
            'success', ('ok', 'branch token', 'repo token'))
 
2069
        client.add_expected_call(
 
2070
            'Branch.get_config_file', ('memory:///', ),
 
2071
            'success', ('ok', ), "# line 1\n")
 
2072
        client.add_expected_call(
 
2073
            'Branch.get_config_file', ('memory:///', ),
 
2074
            'success', ('ok', ), "# line 1\n")
 
2075
        client.add_expected_call(
 
2076
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2077
            'repo token'),
 
2078
            'success', ('ok',))
 
2079
        client.add_expected_call(
 
2080
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2081
            'success', ('ok',))
 
2082
        transport = MemoryTransport()
 
2083
        branch = self.make_remote_branch(transport, client)
 
2084
        branch.lock_write()
 
2085
        config = branch.get_config_stack()
 
2086
        config.set('email', 'The Dude <lebowski@example.com>')
 
2087
        branch.unlock()
 
2088
        self.assertFinished(client)
 
2089
        self.assertEqual(
 
2090
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2091
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2092
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2093
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2094
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2095
                 ('memory:///', 'branch token', 'repo token'),
 
2096
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2097
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2098
            client._calls)
 
2099
 
1642
2100
 
1643
2101
class TestBranchLockWrite(RemoteBranchTestCase):
1644
2102
 
1658
2116
        self.assertFinished(client)
1659
2117
 
1660
2118
 
 
2119
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2120
 
 
2121
    def test_simple(self):
 
2122
        transport = MemoryTransport()
 
2123
        client = FakeClient(transport.base)
 
2124
        client.add_expected_call(
 
2125
            'Branch.get_stacked_on_url', ('quack/',),
 
2126
            'error', ('NotStacked',),)
 
2127
        client.add_expected_call(
 
2128
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2129
            'success', ('ok', '0',),)
 
2130
        client.add_expected_call(
 
2131
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2132
            'error', ('NoSuchRevision', 'unknown',),)
 
2133
        transport.mkdir('quack')
 
2134
        transport = transport.clone('quack')
 
2135
        branch = self.make_remote_branch(transport, client)
 
2136
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2137
        self.assertRaises(errors.NoSuchRevision,
 
2138
            branch.revision_id_to_revno, 'unknown')
 
2139
        self.assertFinished(client)
 
2140
 
 
2141
    def test_dotted(self):
 
2142
        transport = MemoryTransport()
 
2143
        client = FakeClient(transport.base)
 
2144
        client.add_expected_call(
 
2145
            'Branch.get_stacked_on_url', ('quack/',),
 
2146
            'error', ('NotStacked',),)
 
2147
        client.add_expected_call(
 
2148
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2149
            'success', ('ok', '0',),)
 
2150
        client.add_expected_call(
 
2151
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2152
            'error', ('NoSuchRevision', 'unknown',),)
 
2153
        transport.mkdir('quack')
 
2154
        transport = transport.clone('quack')
 
2155
        branch = self.make_remote_branch(transport, client)
 
2156
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2157
        self.assertRaises(errors.NoSuchRevision,
 
2158
            branch.revision_id_to_dotted_revno, 'unknown')
 
2159
        self.assertFinished(client)
 
2160
 
 
2161
    def test_dotted_no_smart_verb(self):
 
2162
        self.setup_smart_server_with_call_log()
 
2163
        branch = self.make_branch('.')
 
2164
        self.disable_verb('Branch.revision_id_to_revno')
 
2165
        self.reset_smart_call_log()
 
2166
        self.assertEquals((0, ),
 
2167
            branch.revision_id_to_dotted_revno('null:'))
 
2168
        self.assertLength(8, self.hpss_calls)
 
2169
 
 
2170
 
1661
2171
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1662
2172
 
1663
2173
    def test__get_config(self):
1677
2187
        self.reset_smart_call_log()
1678
2188
        config = bzrdir.get_config()
1679
2189
        config.set_default_stack_on('/')
1680
 
        self.assertLength(3, self.hpss_calls)
 
2190
        self.assertLength(4, self.hpss_calls)
1681
2191
 
1682
2192
    def test_backwards_compat_get_option(self):
1683
2193
        self.setup_smart_server_with_call_log()
1687
2197
        self.reset_smart_call_log()
1688
2198
        self.assertEqual(None,
1689
2199
            bzrdir._get_config().get_option('default_stack_on'))
1690
 
        self.assertLength(3, self.hpss_calls)
 
2200
        self.assertLength(4, self.hpss_calls)
1691
2201
 
1692
2202
 
1693
2203
class TestTransportIsReadonly(tests.TestCase):
1780
2290
        client = FakeClient(transport.base)
1781
2291
        transport = transport.clone(transport_path)
1782
2292
        # we do not want bzrdir to make any remote calls
1783
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2293
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1784
2294
            _client=False)
1785
2295
        repo = RemoteRepository(bzrdir, None, _client=client)
1786
2296
        return repo, client
1794
2304
 
1795
2305
    def test_get_format_description(self):
1796
2306
        remote_format = RemoteBranchFormat()
1797
 
        real_format = branch.BranchFormat.get_default_format()
 
2307
        real_format = branch.format_registry.get_default()
1798
2308
        remote_format._network_name = real_format.network_name()
1799
2309
        self.assertEqual(remoted_description(real_format),
1800
2310
            remote_format.get_format_description())
1803
2313
class TestRepositoryFormat(TestRemoteRepository):
1804
2314
 
1805
2315
    def test_fast_delta(self):
1806
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2316
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1807
2317
        true_format = RemoteRepositoryFormat()
1808
2318
        true_format._network_name = true_name
1809
2319
        self.assertEqual(True, true_format.fast_deltas)
1810
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2320
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1811
2321
        false_format = RemoteRepositoryFormat()
1812
2322
        false_format._network_name = false_name
1813
2323
        self.assertEqual(False, false_format.fast_deltas)
1814
2324
 
1815
2325
    def test_get_format_description(self):
1816
2326
        remote_repo_format = RemoteRepositoryFormat()
1817
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2327
        real_format = repository.format_registry.get_default()
1818
2328
        remote_repo_format._network_name = real_format.network_name()
1819
2329
        self.assertEqual(remoted_description(real_format),
1820
2330
            remote_repo_format.get_format_description())
1821
2331
 
1822
2332
 
 
2333
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2334
 
 
2335
    def test_empty(self):
 
2336
        transport_path = 'quack'
 
2337
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2338
        client.add_success_response_with_body('', 'ok')
 
2339
        self.assertEquals([], repo.all_revision_ids())
 
2340
        self.assertEqual(
 
2341
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2342
             ('quack/',))],
 
2343
            client._calls)
 
2344
 
 
2345
    def test_with_some_content(self):
 
2346
        transport_path = 'quack'
 
2347
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2348
        client.add_success_response_with_body(
 
2349
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2350
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2351
            repo.all_revision_ids())
 
2352
        self.assertEqual(
 
2353
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2354
             ('quack/',))],
 
2355
            client._calls)
 
2356
 
 
2357
 
1823
2358
class TestRepositoryGatherStats(TestRemoteRepository):
1824
2359
 
1825
2360
    def test_revid_none(self):
1878
2413
                         result)
1879
2414
 
1880
2415
 
 
2416
class TestRepositoryBreakLock(TestRemoteRepository):
 
2417
 
 
2418
    def test_break_lock(self):
 
2419
        transport_path = 'quack'
 
2420
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2421
        client.add_success_response('ok')
 
2422
        repo.break_lock()
 
2423
        self.assertEqual(
 
2424
            [('call', 'Repository.break_lock', ('quack/',))],
 
2425
            client._calls)
 
2426
 
 
2427
 
 
2428
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2429
 
 
2430
    def test_get_serializer_format(self):
 
2431
        transport_path = 'hill'
 
2432
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2433
        client.add_success_response('ok', '7')
 
2434
        self.assertEquals('7', repo.get_serializer_format())
 
2435
        self.assertEqual(
 
2436
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2437
              ('hill/', ))],
 
2438
            client._calls)
 
2439
 
 
2440
 
 
2441
class TestRepositoryReconcile(TestRemoteRepository):
 
2442
 
 
2443
    def test_reconcile(self):
 
2444
        transport_path = 'hill'
 
2445
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2446
        body = ("garbage_inventories: 2\n"
 
2447
                "inconsistent_parents: 3\n")
 
2448
        client.add_expected_call(
 
2449
            'Repository.lock_write', ('hill/', ''),
 
2450
            'success', ('ok', 'a token'))
 
2451
        client.add_success_response_with_body(body, 'ok')
 
2452
        reconciler = repo.reconcile()
 
2453
        self.assertEqual(
 
2454
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2455
             ('call_expecting_body', 'Repository.reconcile',
 
2456
                ('hill/', 'a token'))],
 
2457
            client._calls)
 
2458
        self.assertEquals(2, reconciler.garbage_inventories)
 
2459
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2460
 
 
2461
 
 
2462
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2463
 
 
2464
    def test_text(self):
 
2465
        # ('ok',), body with signature text
 
2466
        transport_path = 'quack'
 
2467
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2468
        client.add_success_response_with_body(
 
2469
            'THETEXT', 'ok')
 
2470
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2471
        self.assertEqual(
 
2472
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2473
             ('quack/', 'revid'))],
 
2474
            client._calls)
 
2475
 
 
2476
    def test_no_signature(self):
 
2477
        transport_path = 'quick'
 
2478
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2479
        client.add_error_response('nosuchrevision', 'unknown')
 
2480
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2481
                "unknown")
 
2482
        self.assertEqual(
 
2483
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2484
              ('quick/', 'unknown'))],
 
2485
            client._calls)
 
2486
 
 
2487
 
1881
2488
class TestRepositoryGetGraph(TestRemoteRepository):
1882
2489
 
1883
2490
    def test_get_graph(self):
1888
2495
        self.assertNotEqual(graph._parents_provider, repo)
1889
2496
 
1890
2497
 
 
2498
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2499
 
 
2500
    def test_add_signature_text(self):
 
2501
        transport_path = 'quack'
 
2502
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2503
        client.add_expected_call(
 
2504
            'Repository.lock_write', ('quack/', ''),
 
2505
            'success', ('ok', 'a token'))
 
2506
        client.add_expected_call(
 
2507
            'Repository.start_write_group', ('quack/', 'a token'),
 
2508
            'success', ('ok', ('token1', )))
 
2509
        client.add_expected_call(
 
2510
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2511
                'token1'),
 
2512
            'success', ('ok', ), None)
 
2513
        repo.lock_write()
 
2514
        repo.start_write_group()
 
2515
        self.assertIs(None,
 
2516
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2517
        self.assertEqual(
 
2518
            ('call_with_body_bytes_expecting_body',
 
2519
              'Repository.add_signature_text',
 
2520
                ('quack/', 'a token', 'rev1', 'token1'),
 
2521
              'every bloody emperor'),
 
2522
            client._calls[-1])
 
2523
 
 
2524
 
1891
2525
class TestRepositoryGetParentMap(TestRemoteRepository):
1892
2526
 
1893
2527
    def test_get_parent_map_caching(self):
1943
2577
        parents = repo.get_parent_map([rev_id])
1944
2578
        self.assertEqual(
1945
2579
            [('call_with_body_bytes_expecting_body',
1946
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1947
 
              rev_id), '\n\n0'),
 
2580
              'Repository.get_parent_map',
 
2581
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1948
2582
             ('disconnect medium',),
1949
2583
             ('call_expecting_body', 'Repository.get_revision_graph',
1950
2584
              ('quack/', ''))],
2070
2704
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2071
2705
        self.assertLength(0, self.hpss_calls)
2072
2706
 
 
2707
    def test_exposes_get_cached_parent_map(self):
 
2708
        """RemoteRepository exposes get_cached_parent_map from
 
2709
        _unstacked_provider
 
2710
        """
 
2711
        r1 = u'\u0e33'.encode('utf8')
 
2712
        r2 = u'\u0dab'.encode('utf8')
 
2713
        lines = [' '.join([r2, r1]), r1]
 
2714
        encoded_body = bz2.compress('\n'.join(lines))
 
2715
 
 
2716
        transport_path = 'quack'
 
2717
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2718
        client.add_success_response_with_body(encoded_body, 'ok')
 
2719
        repo.lock_read()
 
2720
        # get_cached_parent_map should *not* trigger an RPC
 
2721
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2722
        self.assertEqual([], client._calls)
 
2723
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2724
        self.assertEqual({r1: (NULL_REVISION,)},
 
2725
            repo.get_cached_parent_map([r1]))
 
2726
        self.assertEqual(
 
2727
            [('call_with_body_bytes_expecting_body',
 
2728
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2729
              '\n\n0')],
 
2730
            client._calls)
 
2731
        repo.unlock()
 
2732
 
2073
2733
 
2074
2734
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2075
2735
 
2090
2750
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2091
2751
 
2092
2752
 
 
2753
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2754
 
 
2755
    def test_hpss_missing_revision(self):
 
2756
        transport_path = 'quack'
 
2757
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2758
        client.add_success_response_with_body(
 
2759
            '', 'ok', '10')
 
2760
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2761
            ['somerev1', 'anotherrev2'])
 
2762
        self.assertEqual(
 
2763
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2764
             ('quack/', ), "somerev1\nanotherrev2")],
 
2765
            client._calls)
 
2766
 
 
2767
    def test_hpss_get_single_revision(self):
 
2768
        transport_path = 'quack'
 
2769
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2770
        somerev1 = Revision("somerev1")
 
2771
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2772
        somerev1.timestamp = 1321828927
 
2773
        somerev1.timezone = -60
 
2774
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2775
        somerev1.message = "Message"
 
2776
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2777
            somerev1))
 
2778
        # Split up body into two bits to make sure the zlib compression object
 
2779
        # gets data fed twice.
 
2780
        client.add_success_response_with_body(
 
2781
                [body[:10], body[10:]], 'ok', '10')
 
2782
        revs = repo.get_revisions(['somerev1'])
 
2783
        self.assertEquals(revs, [somerev1])
 
2784
        self.assertEqual(
 
2785
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2786
             ('quack/', ), "somerev1")],
 
2787
            client._calls)
 
2788
 
 
2789
 
2093
2790
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2094
2791
 
2095
2792
    def test_null_revision(self):
2191
2888
        """
2192
2889
        # Make a repo with a fallback repo, both using a FakeClient.
2193
2890
        format = remote.response_tuple_to_repo_format(
2194
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2891
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2195
2892
        repo, client = self.setup_fake_client_and_repository('quack')
2196
2893
        repo._format = format
2197
2894
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2198
2895
            'fallback')
2199
2896
        fallback_repo._client = client
 
2897
        fallback_repo._format = format
2200
2898
        repo.add_fallback_repository(fallback_repo)
2201
2899
        # First the client should ask the primary repo
2202
2900
        client.add_expected_call(
2231
2929
        self.setup_smart_server_with_call_log()
2232
2930
        tree = self.make_branch_and_memory_tree('.')
2233
2931
        tree.lock_write()
 
2932
        tree.add('')
2234
2933
        rev1 = tree.commit('First')
2235
2934
        rev2 = tree.commit('Second')
2236
2935
        tree.unlock()
2244
2943
                              call.call.method == verb])
2245
2944
 
2246
2945
 
 
2946
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2947
 
 
2948
    def test_has_signature_for_revision_id(self):
 
2949
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2950
        transport_path = 'quack'
 
2951
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2952
        client.add_success_response('yes')
 
2953
        result = repo.has_signature_for_revision_id('A')
 
2954
        self.assertEqual(
 
2955
            [('call', 'Repository.has_signature_for_revision_id',
 
2956
              ('quack/', 'A'))],
 
2957
            client._calls)
 
2958
        self.assertEqual(True, result)
 
2959
 
 
2960
    def test_is_not_shared(self):
 
2961
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2962
        transport_path = 'qwack'
 
2963
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2964
        client.add_success_response('no')
 
2965
        result = repo.has_signature_for_revision_id('A')
 
2966
        self.assertEqual(
 
2967
            [('call', 'Repository.has_signature_for_revision_id',
 
2968
              ('qwack/', 'A'))],
 
2969
            client._calls)
 
2970
        self.assertEqual(False, result)
 
2971
 
 
2972
 
 
2973
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2974
 
 
2975
    def test_get_physical_lock_status_yes(self):
 
2976
        transport_path = 'qwack'
 
2977
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2978
        client.add_success_response('yes')
 
2979
        result = repo.get_physical_lock_status()
 
2980
        self.assertEqual(
 
2981
            [('call', 'Repository.get_physical_lock_status',
 
2982
              ('qwack/', ))],
 
2983
            client._calls)
 
2984
        self.assertEqual(True, result)
 
2985
 
 
2986
    def test_get_physical_lock_status_no(self):
 
2987
        transport_path = 'qwack'
 
2988
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2989
        client.add_success_response('no')
 
2990
        result = repo.get_physical_lock_status()
 
2991
        self.assertEqual(
 
2992
            [('call', 'Repository.get_physical_lock_status',
 
2993
              ('qwack/', ))],
 
2994
            client._calls)
 
2995
        self.assertEqual(False, result)
 
2996
 
 
2997
 
2247
2998
class TestRepositoryIsShared(TestRemoteRepository):
2248
2999
 
2249
3000
    def test_is_shared(self):
2269
3020
        self.assertEqual(False, result)
2270
3021
 
2271
3022
 
 
3023
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3024
 
 
3025
    def test_make_working_trees(self):
 
3026
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3027
        transport_path = 'quack'
 
3028
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3029
        client.add_success_response('yes')
 
3030
        result = repo.make_working_trees()
 
3031
        self.assertEqual(
 
3032
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3033
            client._calls)
 
3034
        self.assertEqual(True, result)
 
3035
 
 
3036
    def test_no_working_trees(self):
 
3037
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3038
        transport_path = 'qwack'
 
3039
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3040
        client.add_success_response('no')
 
3041
        result = repo.make_working_trees()
 
3042
        self.assertEqual(
 
3043
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3044
            client._calls)
 
3045
        self.assertEqual(False, result)
 
3046
 
 
3047
 
2272
3048
class TestRepositoryLockWrite(TestRemoteRepository):
2273
3049
 
2274
3050
    def test_lock_write(self):
2275
3051
        transport_path = 'quack'
2276
3052
        repo, client = self.setup_fake_client_and_repository(transport_path)
2277
3053
        client.add_success_response('ok', 'a token')
2278
 
        result = repo.lock_write()
 
3054
        token = repo.lock_write().repository_token
2279
3055
        self.assertEqual(
2280
3056
            [('call', 'Repository.lock_write', ('quack/', ''))],
2281
3057
            client._calls)
2282
 
        self.assertEqual('a token', result)
 
3058
        self.assertEqual('a token', token)
2283
3059
 
2284
3060
    def test_lock_write_already_locked(self):
2285
3061
        transport_path = 'quack'
2300
3076
            client._calls)
2301
3077
 
2302
3078
 
 
3079
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3080
 
 
3081
    def test_start_write_group(self):
 
3082
        transport_path = 'quack'
 
3083
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3084
        client.add_expected_call(
 
3085
            'Repository.lock_write', ('quack/', ''),
 
3086
            'success', ('ok', 'a token'))
 
3087
        client.add_expected_call(
 
3088
            'Repository.start_write_group', ('quack/', 'a token'),
 
3089
            'success', ('ok', ('token1', )))
 
3090
        repo.lock_write()
 
3091
        repo.start_write_group()
 
3092
 
 
3093
    def test_start_write_group_unsuspendable(self):
 
3094
        # Some repositories do not support suspending write
 
3095
        # groups. For those, fall back to the "real" repository.
 
3096
        transport_path = 'quack'
 
3097
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3098
        def stub_ensure_real():
 
3099
            client._calls.append(('_ensure_real',))
 
3100
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3101
        repo._ensure_real = stub_ensure_real
 
3102
        client.add_expected_call(
 
3103
            'Repository.lock_write', ('quack/', ''),
 
3104
            'success', ('ok', 'a token'))
 
3105
        client.add_expected_call(
 
3106
            'Repository.start_write_group', ('quack/', 'a token'),
 
3107
            'error', ('UnsuspendableWriteGroup',))
 
3108
        repo.lock_write()
 
3109
        repo.start_write_group()
 
3110
        self.assertEquals(client._calls[-2:], [ 
 
3111
            ('_ensure_real',),
 
3112
            ('start_write_group',)])
 
3113
 
 
3114
    def test_commit_write_group(self):
 
3115
        transport_path = 'quack'
 
3116
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3117
        client.add_expected_call(
 
3118
            'Repository.lock_write', ('quack/', ''),
 
3119
            'success', ('ok', 'a token'))
 
3120
        client.add_expected_call(
 
3121
            'Repository.start_write_group', ('quack/', 'a token'),
 
3122
            'success', ('ok', ['token1']))
 
3123
        client.add_expected_call(
 
3124
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3125
            'success', ('ok',))
 
3126
        repo.lock_write()
 
3127
        repo.start_write_group()
 
3128
        repo.commit_write_group()
 
3129
 
 
3130
    def test_abort_write_group(self):
 
3131
        transport_path = 'quack'
 
3132
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3133
        client.add_expected_call(
 
3134
            'Repository.lock_write', ('quack/', ''),
 
3135
            'success', ('ok', 'a token'))
 
3136
        client.add_expected_call(
 
3137
            'Repository.start_write_group', ('quack/', 'a token'),
 
3138
            'success', ('ok', ['token1']))
 
3139
        client.add_expected_call(
 
3140
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3141
            'success', ('ok',))
 
3142
        repo.lock_write()
 
3143
        repo.start_write_group()
 
3144
        repo.abort_write_group(False)
 
3145
 
 
3146
    def test_suspend_write_group(self):
 
3147
        transport_path = 'quack'
 
3148
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3149
        self.assertEquals([], repo.suspend_write_group())
 
3150
 
 
3151
    def test_resume_write_group(self):
 
3152
        transport_path = 'quack'
 
3153
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3154
        client.add_expected_call(
 
3155
            'Repository.lock_write', ('quack/', ''),
 
3156
            'success', ('ok', 'a token'))
 
3157
        client.add_expected_call(
 
3158
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3159
            'success', ('ok',))
 
3160
        repo.lock_write()
 
3161
        repo.resume_write_group(['token1'])
 
3162
 
 
3163
 
2303
3164
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2304
3165
 
2305
3166
    def test_backwards_compat(self):
2364
3225
        self.assertEqual([], client._calls)
2365
3226
 
2366
3227
 
 
3228
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3229
    """Test Repository.iter_file_bytes."""
 
3230
 
 
3231
    def test_single(self):
 
3232
        transport_path = 'quack'
 
3233
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3234
        client.add_expected_call(
 
3235
            'Repository.iter_files_bytes', ('quack/', ),
 
3236
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3237
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3238
                "somerev", "myid")]):
 
3239
            self.assertEquals("myid", identifier)
 
3240
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3241
 
 
3242
    def test_missing(self):
 
3243
        transport_path = 'quack'
 
3244
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3245
        client.add_expected_call(
 
3246
            'Repository.iter_files_bytes',
 
3247
                ('quack/', ),
 
3248
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3249
            iter(["absent\0somefile\0somerev\n"]))
 
3250
        self.assertRaises(errors.RevisionNotPresent, list,
 
3251
                repo.iter_files_bytes(
 
3252
                [("somefile", "somerev", "myid")]))
 
3253
 
 
3254
 
2367
3255
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2368
3256
    """Base class for Repository.insert_stream and .insert_stream_1.19
2369
3257
    tests.
2376
3264
        the client is finished.
2377
3265
        """
2378
3266
        sink = repo._get_sink()
2379
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3267
        fmt = repository.format_registry.get_default()
2380
3268
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2381
3269
        self.assertEqual([], resume_tokens)
2382
3270
        self.assertEqual(set(), missing_keys)
2482
3370
                return True
2483
3371
        repo._real_repository = FakeRealRepository()
2484
3372
        sink = repo._get_sink()
2485
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3373
        fmt = repository.format_registry.get_default()
2486
3374
        stream = self.make_stream_with_inv_deltas(fmt)
2487
3375
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2488
3376
        # Every record from the first inventory delta should have been sent to
2644
3532
        self.calls = calls
2645
3533
        self._pack_collection = _StubPackCollection(calls)
2646
3534
 
 
3535
    def start_write_group(self):
 
3536
        self.calls.append(('start_write_group',))
 
3537
 
2647
3538
    def is_in_write_group(self):
2648
3539
        return False
2649
3540
 
2708
3599
             ('pack collection autopack',)],
2709
3600
            client._calls)
2710
3601
 
 
3602
    def test_oom_error_reporting(self):
 
3603
        """An out-of-memory condition on the server is reported clearly"""
 
3604
        transport_path = 'quack'
 
3605
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3606
        client.add_expected_call(
 
3607
            'PackRepository.autopack', ('quack/',),
 
3608
            'error', ('MemoryError',))
 
3609
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3610
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3611
 
2711
3612
 
2712
3613
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2713
3614
    """Base class for unit tests for bzrlib.remote._translate_error."""
2786
3687
            detail='extra detail')
2787
3688
        self.assertEqual(expected_error, translated_error)
2788
3689
 
 
3690
    def test_norepository(self):
 
3691
        bzrdir = self.make_bzrdir('')
 
3692
        translated_error = self.translateTuple(('norepository',),
 
3693
            bzrdir=bzrdir)
 
3694
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3695
        self.assertEqual(expected_error, translated_error)
 
3696
 
2789
3697
    def test_LockContention(self):
2790
3698
        translated_error = self.translateTuple(('LockContention',))
2791
3699
        expected_error = errors.LockContention('(remote lock)')
2819
3727
        expected_error = errors.DivergedBranches(branch, other_branch)
2820
3728
        self.assertEqual(expected_error, translated_error)
2821
3729
 
 
3730
    def test_NotStacked(self):
 
3731
        branch = self.make_branch('')
 
3732
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3733
        expected_error = errors.NotStacked(branch)
 
3734
        self.assertEqual(expected_error, translated_error)
 
3735
 
2822
3736
    def test_ReadError_no_args(self):
2823
3737
        path = 'a path'
2824
3738
        translated_error = self.translateTuple(('ReadError',), path=path)
2840
3754
 
2841
3755
    def test_PermissionDenied_no_args(self):
2842
3756
        path = 'a path'
2843
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3757
        translated_error = self.translateTuple(('PermissionDenied',),
 
3758
            path=path)
2844
3759
        expected_error = errors.PermissionDenied(path)
2845
3760
        self.assertEqual(expected_error, translated_error)
2846
3761
 
2869
3784
        expected_error = errors.PermissionDenied(path, extra)
2870
3785
        self.assertEqual(expected_error, translated_error)
2871
3786
 
 
3787
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3788
 
 
3789
    def test_NoSuchFile_context_path(self):
 
3790
        local_path = "local path"
 
3791
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3792
            path=local_path)
 
3793
        expected_error = errors.ReadError(local_path)
 
3794
        self.assertEqual(expected_error, translated_error)
 
3795
 
 
3796
    def test_NoSuchFile_without_context(self):
 
3797
        remote_path = "remote path"
 
3798
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3799
        expected_error = errors.ReadError(remote_path)
 
3800
        self.assertEqual(expected_error, translated_error)
 
3801
 
 
3802
    def test_ReadOnlyError(self):
 
3803
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3804
        expected_error = errors.TransportNotPossible("readonly transport")
 
3805
        self.assertEqual(expected_error, translated_error)
 
3806
 
 
3807
    def test_MemoryError(self):
 
3808
        translated_error = self.translateTuple(('MemoryError',))
 
3809
        self.assertStartsWith(str(translated_error),
 
3810
            "remote server out of memory")
 
3811
 
 
3812
    def test_generic_IndexError_no_classname(self):
 
3813
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3814
        translated_error = self.translateErrorFromSmartServer(err)
 
3815
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3816
        self.assertEqual(expected_error, translated_error)
 
3817
 
 
3818
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3819
 
 
3820
    def test_generic_KeyError(self):
 
3821
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3822
        translated_error = self.translateErrorFromSmartServer(err)
 
3823
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3824
        self.assertEqual(expected_error, translated_error)
 
3825
 
2872
3826
 
2873
3827
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2874
3828
    """Unit tests for bzrlib.remote._translate_error's robustness.
3019
3973
        _, stacked = branch_factory()
3020
3974
        source = stacked.repository._get_source(target_repository_format)
3021
3975
        tip = stacked.last_revision()
3022
 
        revs = stacked.repository.get_ancestry(tip)
3023
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3976
        stacked.repository._ensure_real()
 
3977
        graph = stacked.repository.get_graph()
 
3978
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3979
                if r != NULL_REVISION]
 
3980
        revs.reverse()
 
3981
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3024
3982
        self.reset_smart_call_log()
3025
3983
        stream = source.get_stream(search)
3026
 
        if None in revs:
3027
 
            revs.remove(None)
3028
3984
        # We trust that if a revision is in the stream the rest of the new
3029
3985
        # content for it is too, as per our main fetch tests; here we are
3030
3986
        # checking that the revisions are actually included at all, and their
3069
4025
        self.assertEqual(expected_revs, rev_ord)
3070
4026
        # Getting topological sort requires VFS calls still - one of which is
3071
4027
        # pushing up from the bound branch.
3072
 
        self.assertLength(13, self.hpss_calls)
 
4028
        self.assertLength(14, self.hpss_calls)
3073
4029
 
3074
4030
    def test_stacked_get_stream_groupcompress(self):
3075
4031
        # Repository._get_source.get_stream() from a stacked repository with
3116
4072
 
3117
4073
    def test_copy_content_into_avoids_revision_history(self):
3118
4074
        local = self.make_branch('local')
3119
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3120
 
        remote_backing_tree.commit("Commit.")
 
4075
        builder = self.make_branch_builder('remote')
 
4076
        builder.build_commit(message="Commit.")
3121
4077
        remote_branch_url = self.smart_server.get_url() + 'remote'
3122
4078
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3123
4079
        local.repository.fetch(remote_branch.repository)
3124
4080
        self.hpss_calls = []
3125
4081
        remote_branch.copy_content_into(local)
3126
4082
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4083
 
 
4084
    def test_fetch_everything_needs_just_one_call(self):
 
4085
        local = self.make_branch('local')
 
4086
        builder = self.make_branch_builder('remote')
 
4087
        builder.build_commit(message="Commit.")
 
4088
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4089
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4090
        self.hpss_calls = []
 
4091
        local.repository.fetch(
 
4092
            remote_branch.repository,
 
4093
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4094
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4095
 
 
4096
    def override_verb(self, verb_name, verb):
 
4097
        request_handlers = request.request_handlers
 
4098
        orig_verb = request_handlers.get(verb_name)
 
4099
        orig_info = request_handlers.get_info(verb_name)
 
4100
        request_handlers.register(verb_name, verb, override_existing=True)
 
4101
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4102
                override_existing=True, info=orig_info)
 
4103
 
 
4104
    def test_fetch_everything_backwards_compat(self):
 
4105
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4106
        
 
4107
        Pre-2.4 do not support 'everything' searches with the
 
4108
        Repository.get_stream_1.19 verb.
 
4109
        """
 
4110
        verb_log = []
 
4111
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4112
            """A version of the Repository.get_stream_1.19 verb patched to
 
4113
            reject 'everything' searches the way 2.3 and earlier do.
 
4114
            """
 
4115
            def recreate_search(self, repository, search_bytes,
 
4116
                                discard_excess=False):
 
4117
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4118
                if search_bytes == 'everything':
 
4119
                    return (None,
 
4120
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4121
                return super(OldGetStreamVerb,
 
4122
                        self).recreate_search(repository, search_bytes,
 
4123
                            discard_excess=discard_excess)
 
4124
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4125
        local = self.make_branch('local')
 
4126
        builder = self.make_branch_builder('remote')
 
4127
        builder.build_commit(message="Commit.")
 
4128
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4129
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4130
        self.hpss_calls = []
 
4131
        local.repository.fetch(
 
4132
            remote_branch.repository,
 
4133
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4134
        # make sure the overridden verb was used
 
4135
        self.assertLength(1, verb_log)
 
4136
        # more than one HPSS call is needed, but because it's a VFS callback
 
4137
        # its hard to predict exactly how many.
 
4138
        self.assertTrue(len(self.hpss_calls) > 1)
 
4139
 
 
4140
 
 
4141
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4142
    tests.TestCaseWithTransport):
 
4143
    """Ensure correct handling of bound_location modifications.
 
4144
 
 
4145
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4146
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4147
    happen in this context.
 
4148
    """
 
4149
 
 
4150
    def setUp(self):
 
4151
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4152
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4153
 
 
4154
    def make_master_and_checkout(self, master_name, checkout_name):
 
4155
        # Create the master branch and its associated checkout
 
4156
        self.master = self.make_branch_and_tree(master_name)
 
4157
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4158
        # Modify the master branch so there is something to update
 
4159
        self.master.commit('add stuff')
 
4160
        self.last_revid = self.master.commit('even more stuff')
 
4161
        self.bound_location = self.checkout.branch.get_bound_location()
 
4162
 
 
4163
    def assertUpdateSucceeds(self, new_location):
 
4164
        self.checkout.branch.set_bound_location(new_location)
 
4165
        self.checkout.update()
 
4166
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4167
 
 
4168
    def test_without_final_slash(self):
 
4169
        self.make_master_and_checkout('master', 'checkout')
 
4170
        # For unclear reasons some users have a bound_location without a final
 
4171
        # '/', simulate that by forcing such a value
 
4172
        self.assertEndsWith(self.bound_location, '/')
 
4173
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4174
 
 
4175
    def test_plus_sign(self):
 
4176
        self.make_master_and_checkout('+master', 'checkout')
 
4177
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4178
 
 
4179
    def test_tilda(self):
 
4180
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4181
        # interpretation
 
4182
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4183
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4184
 
 
4185
 
 
4186
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4187
 
 
4188
    def test_no_context(self):
 
4189
        class OutOfCoffee(errors.BzrError):
 
4190
            """A dummy exception for testing."""
 
4191
 
 
4192
            def __init__(self, urgency):
 
4193
                self.urgency = urgency
 
4194
        remote.no_context_error_translators.register("OutOfCoffee",
 
4195
            lambda err: OutOfCoffee(err.error_args[0]))
 
4196
        transport = MemoryTransport()
 
4197
        client = FakeClient(transport.base)
 
4198
        client.add_expected_call(
 
4199
            'Branch.get_stacked_on_url', ('quack/',),
 
4200
            'error', ('NotStacked',))
 
4201
        client.add_expected_call(
 
4202
            'Branch.last_revision_info',
 
4203
            ('quack/',),
 
4204
            'error', ('OutOfCoffee', 'low'))
 
4205
        transport.mkdir('quack')
 
4206
        transport = transport.clone('quack')
 
4207
        branch = self.make_remote_branch(transport, client)
 
4208
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4209
        self.assertFinished(client)
 
4210
 
 
4211
    def test_with_context(self):
 
4212
        class OutOfTea(errors.BzrError):
 
4213
            def __init__(self, branch, urgency):
 
4214
                self.branch = branch
 
4215
                self.urgency = urgency
 
4216
        remote.error_translators.register("OutOfTea",
 
4217
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4218
                find("branch")))
 
4219
        transport = MemoryTransport()
 
4220
        client = FakeClient(transport.base)
 
4221
        client.add_expected_call(
 
4222
            'Branch.get_stacked_on_url', ('quack/',),
 
4223
            'error', ('NotStacked',))
 
4224
        client.add_expected_call(
 
4225
            'Branch.last_revision_info',
 
4226
            ('quack/',),
 
4227
            'error', ('OutOfTea', 'low'))
 
4228
        transport.mkdir('quack')
 
4229
        transport = transport.clone('quack')
 
4230
        branch = self.make_remote_branch(transport, client)
 
4231
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4232
        self.assertFinished(client)
 
4233
 
 
4234
 
 
4235
class TestRepositoryPack(TestRemoteRepository):
 
4236
 
 
4237
    def test_pack(self):
 
4238
        transport_path = 'quack'
 
4239
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4240
        client.add_expected_call(
 
4241
            'Repository.lock_write', ('quack/', ''),
 
4242
            'success', ('ok', 'token'))
 
4243
        client.add_expected_call(
 
4244
            'Repository.pack', ('quack/', 'token', 'False'),
 
4245
            'success', ('ok',), )
 
4246
        client.add_expected_call(
 
4247
            'Repository.unlock', ('quack/', 'token'),
 
4248
            'success', ('ok', ))
 
4249
        repo.pack()
 
4250
 
 
4251
    def test_pack_with_hint(self):
 
4252
        transport_path = 'quack'
 
4253
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4254
        client.add_expected_call(
 
4255
            'Repository.lock_write', ('quack/', ''),
 
4256
            'success', ('ok', 'token'))
 
4257
        client.add_expected_call(
 
4258
            'Repository.pack', ('quack/', 'token', 'False'),
 
4259
            'success', ('ok',), )
 
4260
        client.add_expected_call(
 
4261
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4262
            'success', ('ok', ))
 
4263
        repo.pack(['hinta', 'hintb'])
 
4264
 
 
4265
 
 
4266
class TestRepositoryIterInventories(TestRemoteRepository):
 
4267
    """Test Repository.iter_inventories."""
 
4268
 
 
4269
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4270
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4271
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4272
 
 
4273
    def test_single_empty(self):
 
4274
        transport_path = 'quack'
 
4275
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4276
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4277
        repo._format = fmt
 
4278
        stream = [('inventory-deltas', [
 
4279
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4280
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4281
        client.add_expected_call(
 
4282
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4283
            'success', ('ok', ),
 
4284
            _stream_to_byte_stream(stream, fmt))
 
4285
        ret = list(repo.iter_inventories(["somerevid"]))
 
4286
        self.assertLength(1, ret)
 
4287
        inv = ret[0]
 
4288
        self.assertEquals("somerevid", inv.revision_id)
 
4289
 
 
4290
    def test_empty(self):
 
4291
        transport_path = 'quack'
 
4292
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4293
        ret = list(repo.iter_inventories([]))
 
4294
        self.assertEquals(ret, [])
 
4295
 
 
4296
    def test_missing(self):
 
4297
        transport_path = 'quack'
 
4298
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4299
        client.add_expected_call(
 
4300
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4301
            'success', ('ok', ), iter([]))
 
4302
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4303
            ["somerevid"]))