~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Wouter van Heyst
  • Date: 2012-01-25 21:13:15 UTC
  • mto: (6437.3.27 2.5)
  • mto: This revision was merged to the branch mainline in revision 6451.
  • Revision ID: larstiq@larstiq.dyndns.org-20120125211315-ch74doua37bqet0i
mechanically replace file().write() pattern with a with-keyword version

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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(["", "foo"], 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
    def test_destroy_named(self):
 
593
        transport = self.get_transport('quack')
 
594
        referenced = self.make_branch('referenced')
 
595
        client = FakeClient(transport.base)
 
596
        client.add_expected_call(
 
597
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
598
            'success', ('ok',)),
 
599
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
600
            _client=client)
 
601
        a_bzrdir.destroy_branch("foo")
 
602
        self.assertFinished(client)
 
603
 
 
604
 
 
605
class TestBzrDirHasWorkingTree(TestRemote):
 
606
 
 
607
    def test_has_workingtree(self):
 
608
        transport = self.get_transport('quack')
 
609
        client = FakeClient(transport.base)
 
610
        client.add_expected_call(
 
611
            'BzrDir.has_workingtree', ('quack/',),
 
612
            'success', ('yes',)),
 
613
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
614
            _client=client)
 
615
        self.assertTrue(a_bzrdir.has_workingtree())
 
616
        self.assertFinished(client)
 
617
 
 
618
    def test_no_workingtree(self):
 
619
        transport = self.get_transport('quack')
 
620
        client = FakeClient(transport.base)
 
621
        client.add_expected_call(
 
622
            'BzrDir.has_workingtree', ('quack/',),
 
623
            'success', ('no',)),
 
624
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
625
            _client=client)
 
626
        self.assertFalse(a_bzrdir.has_workingtree())
 
627
        self.assertFinished(client)
 
628
 
 
629
 
 
630
class TestBzrDirDestroyRepository(TestRemote):
 
631
 
 
632
    def test_destroy_repository(self):
 
633
        transport = self.get_transport('quack')
 
634
        client = FakeClient(transport.base)
 
635
        client.add_expected_call(
 
636
            'BzrDir.destroy_repository', ('quack/',),
 
637
            'success', ('ok',)),
 
638
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
639
            _client=client)
 
640
        a_bzrdir.destroy_repository()
 
641
        self.assertFinished(client)
 
642
 
480
643
 
481
644
class TestBzrDirOpen(TestRemote):
482
645
 
492
655
        client.add_expected_call(
493
656
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
494
657
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
495
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
658
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
496
659
        self.assertFinished(client)
497
660
 
498
661
    def test_present_without_workingtree(self):
499
662
        client, transport = self.make_fake_client_and_transport()
500
663
        client.add_expected_call(
501
664
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
502
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
665
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
503
666
            _client=client, _force_probe=True)
504
667
        self.assertIsInstance(bd, RemoteBzrDir)
505
668
        self.assertFalse(bd.has_workingtree())
510
673
        client, transport = self.make_fake_client_and_transport()
511
674
        client.add_expected_call(
512
675
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
513
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
676
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
514
677
            _client=client, _force_probe=True)
515
678
        self.assertIsInstance(bd, RemoteBzrDir)
516
679
        self.assertTrue(bd.has_workingtree())
523
686
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
524
687
        client.add_expected_call(
525
688
            'BzrDir.open', ('quack/',), 'success', ('yes',))
526
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
689
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
690
            _client=client, _force_probe=True)
 
691
        self.assertIsInstance(bd, RemoteBzrDir)
 
692
        self.assertFinished(client)
 
693
 
 
694
    def test_backwards_compat_hpss_v2(self):
 
695
        client, transport = self.make_fake_client_and_transport()
 
696
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
697
        # server: upon first RPC call detect the protocol version, and because
 
698
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
699
        # continuing with the RPC.
 
700
        orig_check_call = client._check_call
 
701
        def check_call(method, args):
 
702
            client._medium._protocol_version = 2
 
703
            client._medium._remember_remote_is_before((1, 6))
 
704
            client._check_call = orig_check_call
 
705
            client._check_call(method, args)
 
706
        client._check_call = check_call
 
707
        client.add_expected_call(
 
708
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
709
        client.add_expected_call(
 
710
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
711
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
527
712
            _client=client, _force_probe=True)
528
713
        self.assertIsInstance(bd, RemoteBzrDir)
529
714
        self.assertFinished(client)
560
745
        client.add_expected_call(
561
746
            'Branch.get_stacked_on_url', ('quack/',),
562
747
            'error', ('NotStacked',))
563
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
748
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
564
749
            _client=client)
565
750
        result = bzrdir.open_branch()
566
751
        self.assertIsInstance(result, RemoteBranch)
573
758
        transport = transport.clone('quack')
574
759
        client = FakeClient(transport.base)
575
760
        client.add_error_response('nobranch')
576
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
761
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
577
762
            _client=client)
578
763
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
579
764
        self.assertEqual(
584
769
        # _get_tree_branch is a form of open_branch, but it should only ask for
585
770
        # branch opening, not any other network requests.
586
771
        calls = []
587
 
        def open_branch():
 
772
        def open_branch(name=None, possible_transports=None):
588
773
            calls.append("Called")
589
774
            return "a-branch"
590
775
        transport = MemoryTransport()
591
776
        # no requests on the network - catches other api calls being made.
592
777
        client = FakeClient(transport.base)
593
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
778
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
594
779
            _client=client)
595
780
        # patch the open_branch call to record that it was called.
596
781
        bzrdir.open_branch = open_branch
615
800
        client.add_expected_call(
616
801
            'Branch.get_stacked_on_url', ('~hello/',),
617
802
            'error', ('NotStacked',))
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
803
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
804
            _client=client)
620
805
        result = bzrdir.open_branch()
621
806
        self.assertFinished(client)
638
823
        client.add_success_response(
639
824
            'ok', '', rich_response, subtree_response, external_lookup,
640
825
            network_name)
641
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
826
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
642
827
            _client=client)
643
828
        result = bzrdir.open_repository()
644
829
        self.assertEqual(
661
846
        old.
662
847
        """
663
848
        self.assertRaises(errors.NotBranchError,
664
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
849
            RemoteBzrProber.probe_transport, OldServerTransport())
665
850
 
666
851
 
667
852
class TestBzrDirCreateBranch(TestRemote):
690
875
            'BzrDir.create_branch', ('quack/', network_name),
691
876
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
692
877
            reference_repo_name))
693
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
878
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
694
879
            _client=client)
695
880
        branch = a_bzrdir.create_branch()
696
881
        # We should have got a remote branch
699
884
        format = branch._format
700
885
        self.assertEqual(network_name, format.network_name())
701
886
 
 
887
    def test_already_open_repo_and_reused_medium(self):
 
888
        """Bug 726584: create_branch(..., repository=repo) should work
 
889
        regardless of what the smart medium's base URL is.
 
890
        """
 
891
        self.transport_server = test_server.SmartTCPServer_for_testing
 
892
        transport = self.get_transport('.')
 
893
        repo = self.make_repository('quack')
 
894
        # Client's medium rooted a transport root (not at the bzrdir)
 
895
        client = FakeClient(transport.base)
 
896
        transport = transport.clone('quack')
 
897
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
898
        reference_format = reference_bzrdir_format.get_branch_format()
 
899
        network_name = reference_format.network_name()
 
900
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
901
        reference_repo_name = reference_repo_fmt.network_name()
 
902
        client.add_expected_call(
 
903
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
904
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
905
            reference_repo_name))
 
906
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
907
            _client=client)
 
908
        branch = a_bzrdir.create_branch(repository=repo)
 
909
        # We should have got a remote branch
 
910
        self.assertIsInstance(branch, remote.RemoteBranch)
 
911
        # its format should have the settings from the response
 
912
        format = branch._format
 
913
        self.assertEqual(network_name, format.network_name())
 
914
 
702
915
 
703
916
class TestBzrDirCreateRepository(TestRemote):
704
917
 
725
938
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
726
939
                'False'),
727
940
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
728
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
941
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
729
942
            _client=client)
730
943
        repo = a_bzrdir.create_repository()
731
944
        # We should have got a remote repository
754
967
        # name.
755
968
        client.add_success_response_with_body(
756
969
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
970
        client.add_success_response('stat', '0', '65535')
757
971
        client.add_success_response_with_body(
758
972
            reference_format.get_format_string(), 'ok')
759
973
        # PackRepository wants to do a stat
760
974
        client.add_success_response('stat', '0', '65535')
761
975
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
762
976
            _client=client)
763
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
977
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
764
978
            _client=client)
765
979
        repo = bzrdir.open_repository()
766
980
        self.assertEqual(
768
982
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
769
983
             ('call', 'BzrDir.find_repository', ('quack/',)),
770
984
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
985
             ('call', 'stat', ('/quack/.bzr',)),
771
986
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
772
987
             ('call', 'stat', ('/quack/.bzr/repository',)),
773
988
             ],
787
1002
        # name.
788
1003
        client.add_success_response_with_body(
789
1004
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
1005
        client.add_success_response('stat', '0', '65535')
790
1006
        client.add_success_response_with_body(
791
1007
            reference_format.get_format_string(), 'ok')
792
1008
        # PackRepository wants to do a stat
793
1009
        client.add_success_response('stat', '0', '65535')
794
1010
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
795
1011
            _client=client)
796
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
1012
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
797
1013
            _client=client)
798
1014
        repo = bzrdir.open_repository()
799
1015
        self.assertEqual(
800
1016
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
801
1017
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
802
1018
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
1019
             ('call', 'stat', ('/quack/.bzr',)),
803
1020
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
804
1021
             ('call', 'stat', ('/quack/.bzr/repository',)),
805
1022
             ],
814
1031
        transport = transport.clone('quack')
815
1032
        client = FakeClient(transport.base)
816
1033
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
817
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1034
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
818
1035
            _client=client)
819
1036
        repo = bzrdir.open_repository()
820
1037
        self.assertEqual(
827
1044
 
828
1045
    def test_success(self):
829
1046
        """Simple test for typical successful call."""
830
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1047
        fmt = RemoteBzrDirFormat()
831
1048
        default_format_name = BzrDirFormat.get_default_format().network_name()
832
1049
        transport = self.get_transport()
833
1050
        client = FakeClient(transport.base)
849
1066
        """Error responses are translated, e.g. 'PermissionDenied' raises the
850
1067
        corresponding error from the client.
851
1068
        """
852
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1069
        fmt = RemoteBzrDirFormat()
853
1070
        default_format_name = BzrDirFormat.get_default_format().network_name()
854
1071
        transport = self.get_transport()
855
1072
        client = FakeClient(transport.base)
873
1090
        """Integration test for error translation."""
874
1091
        transport = self.make_smart_server('foo')
875
1092
        transport = transport.clone('no-such-path')
876
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1093
        fmt = RemoteBzrDirFormat()
877
1094
        err = self.assertRaises(errors.NoSuchFile,
878
1095
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
879
1096
 
910
1127
 
911
1128
    def make_remote_bzrdir(self, transport, client):
912
1129
        """Make a RemotebzrDir using 'client' as the _client."""
913
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1130
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
914
1131
            _client=client)
915
1132
 
916
1133
 
942
1159
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
943
1160
 
944
1161
 
 
1162
class TestBranchBreakLock(RemoteBranchTestCase):
 
1163
 
 
1164
    def test_break_lock(self):
 
1165
        transport_path = 'quack'
 
1166
        transport = MemoryTransport()
 
1167
        client = FakeClient(transport.base)
 
1168
        client.add_expected_call(
 
1169
            'Branch.get_stacked_on_url', ('quack/',),
 
1170
            'error', ('NotStacked',))
 
1171
        client.add_expected_call(
 
1172
            'Branch.break_lock', ('quack/',),
 
1173
            'success', ('ok',))
 
1174
        transport.mkdir('quack')
 
1175
        transport = transport.clone('quack')
 
1176
        branch = self.make_remote_branch(transport, client)
 
1177
        branch.break_lock()
 
1178
        self.assertFinished(client)
 
1179
 
 
1180
 
 
1181
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1182
 
 
1183
    def test_get_physical_lock_status_yes(self):
 
1184
        transport = MemoryTransport()
 
1185
        client = FakeClient(transport.base)
 
1186
        client.add_expected_call(
 
1187
            'Branch.get_stacked_on_url', ('quack/',),
 
1188
            'error', ('NotStacked',))
 
1189
        client.add_expected_call(
 
1190
            'Branch.get_physical_lock_status', ('quack/',),
 
1191
            'success', ('yes',))
 
1192
        transport.mkdir('quack')
 
1193
        transport = transport.clone('quack')
 
1194
        branch = self.make_remote_branch(transport, client)
 
1195
        result = branch.get_physical_lock_status()
 
1196
        self.assertFinished(client)
 
1197
        self.assertEqual(True, result)
 
1198
 
 
1199
    def test_get_physical_lock_status_no(self):
 
1200
        transport = MemoryTransport()
 
1201
        client = FakeClient(transport.base)
 
1202
        client.add_expected_call(
 
1203
            'Branch.get_stacked_on_url', ('quack/',),
 
1204
            'error', ('NotStacked',))
 
1205
        client.add_expected_call(
 
1206
            'Branch.get_physical_lock_status', ('quack/',),
 
1207
            'success', ('no',))
 
1208
        transport.mkdir('quack')
 
1209
        transport = transport.clone('quack')
 
1210
        branch = self.make_remote_branch(transport, client)
 
1211
        result = branch.get_physical_lock_status()
 
1212
        self.assertFinished(client)
 
1213
        self.assertEqual(False, result)
 
1214
 
 
1215
 
945
1216
class TestBranchGetParent(RemoteBranchTestCase):
946
1217
 
947
1218
    def test_no_parent(self):
1037
1308
        verb = 'Branch.set_parent_location'
1038
1309
        self.disable_verb(verb)
1039
1310
        branch.set_parent('http://foo/')
1040
 
        self.assertLength(12, self.hpss_calls)
 
1311
        self.assertLength(13, self.hpss_calls)
1041
1312
 
1042
1313
 
1043
1314
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1118
1389
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1119
1390
 
1120
1391
 
 
1392
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1393
 
 
1394
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1395
        transport = MemoryTransport()
 
1396
        client = FakeClient(transport.base)
 
1397
        client.add_expected_call(
 
1398
            'Branch.get_stacked_on_url', ('quack/',),
 
1399
            'error', ('NotStacked',))
 
1400
        client.add_expected_call(
 
1401
            'Branch.last_revision_info', ('quack/',),
 
1402
            'success', ('ok', '1', 'rev-tip'))
 
1403
        client.add_expected_call(
 
1404
            'Branch.get_config_file', ('quack/',),
 
1405
            'success', ('ok',), '')
 
1406
        transport.mkdir('quack')
 
1407
        transport = transport.clone('quack')
 
1408
        branch = self.make_remote_branch(transport, client)
 
1409
        result = branch.heads_to_fetch()
 
1410
        self.assertFinished(client)
 
1411
        self.assertEqual((set(['rev-tip']), set()), result)
 
1412
 
 
1413
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1414
        transport = MemoryTransport()
 
1415
        client = FakeClient(transport.base)
 
1416
        client.add_expected_call(
 
1417
            'Branch.get_stacked_on_url', ('quack/',),
 
1418
            'error', ('NotStacked',))
 
1419
        client.add_expected_call(
 
1420
            'Branch.last_revision_info', ('quack/',),
 
1421
            'success', ('ok', '1', 'rev-tip'))
 
1422
        client.add_expected_call(
 
1423
            'Branch.get_config_file', ('quack/',),
 
1424
            'success', ('ok',), 'branch.fetch_tags = True')
 
1425
        # XXX: this will break if the default format's serialization of tags
 
1426
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1427
        client.add_expected_call(
 
1428
            'Branch.get_tags_bytes', ('quack/',),
 
1429
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1430
        transport.mkdir('quack')
 
1431
        transport = transport.clone('quack')
 
1432
        branch = self.make_remote_branch(transport, client)
 
1433
        result = branch.heads_to_fetch()
 
1434
        self.assertFinished(client)
 
1435
        self.assertEqual(
 
1436
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1437
 
 
1438
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1439
        transport = MemoryTransport()
 
1440
        client = FakeClient(transport.base)
 
1441
        client.add_expected_call(
 
1442
            'Branch.get_stacked_on_url', ('quack/',),
 
1443
            'error', ('NotStacked',))
 
1444
        client.add_expected_call(
 
1445
            'Branch.heads_to_fetch', ('quack/',),
 
1446
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1447
        transport.mkdir('quack')
 
1448
        transport = transport.clone('quack')
 
1449
        branch = self.make_remote_branch(transport, client)
 
1450
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1451
        result = branch.heads_to_fetch()
 
1452
        self.assertFinished(client)
 
1453
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1454
 
 
1455
    def make_branch_with_tags(self):
 
1456
        self.setup_smart_server_with_call_log()
 
1457
        # Make a branch with a single revision.
 
1458
        builder = self.make_branch_builder('foo')
 
1459
        builder.start_series()
 
1460
        builder.build_snapshot('tip', None, [
 
1461
            ('add', ('', 'root-id', 'directory', ''))])
 
1462
        builder.finish_series()
 
1463
        branch = builder.get_branch()
 
1464
        # Add two tags to that branch
 
1465
        branch.tags.set_tag('tag-1', 'rev-1')
 
1466
        branch.tags.set_tag('tag-2', 'rev-2')
 
1467
        return branch
 
1468
 
 
1469
    def test_backwards_compatible(self):
 
1470
        branch = self.make_branch_with_tags()
 
1471
        c = branch.get_config_stack()
 
1472
        c.set('branch.fetch_tags', True)
 
1473
        self.addCleanup(branch.lock_read().unlock)
 
1474
        # Disable the heads_to_fetch verb
 
1475
        verb = 'Branch.heads_to_fetch'
 
1476
        self.disable_verb(verb)
 
1477
        self.reset_smart_call_log()
 
1478
        result = branch.heads_to_fetch()
 
1479
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1480
        self.assertEqual(
 
1481
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1482
             'Branch.get_tags_bytes'],
 
1483
            [call.call.method for call in self.hpss_calls])
 
1484
 
 
1485
    def test_backwards_compatible_no_tags(self):
 
1486
        branch = self.make_branch_with_tags()
 
1487
        c = branch.get_config_stack()
 
1488
        c.set('branch.fetch_tags', False)
 
1489
        self.addCleanup(branch.lock_read().unlock)
 
1490
        # Disable the heads_to_fetch verb
 
1491
        verb = 'Branch.heads_to_fetch'
 
1492
        self.disable_verb(verb)
 
1493
        self.reset_smart_call_log()
 
1494
        result = branch.heads_to_fetch()
 
1495
        self.assertEqual((set(['tip']), set()), result)
 
1496
        self.assertEqual(
 
1497
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1498
            [call.call.method for call in self.hpss_calls])
 
1499
 
 
1500
 
1121
1501
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1122
1502
 
1123
1503
    def test_empty_branch(self):
1178
1558
        client.add_expected_call(
1179
1559
            'Branch.get_stacked_on_url', ('stacked/',),
1180
1560
            'success', ('ok', vfs_url))
1181
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1561
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1182
1562
            _client=client)
1183
1563
        repo_fmt = remote.RemoteRepositoryFormat()
1184
1564
        repo_fmt._custom_format = stacked_branch.repository._format
1211
1591
        # this will also do vfs access, but that goes direct to the transport
1212
1592
        # and isn't seen by the FakeClient.
1213
1593
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1214
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1594
            RemoteBzrDirFormat(), _client=client)
1215
1595
        branch = bzrdir.open_branch()
1216
1596
        result = branch.get_stacked_on_url()
1217
1597
        self.assertEqual('../base', result)
1223
1603
            len(branch.repository._real_repository._fallback_repositories))
1224
1604
 
1225
1605
    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')
 
1606
        base_branch = self.make_branch('base')
 
1607
        stacked_branch = self.make_branch('stacked')
1228
1608
        stacked_branch.set_stacked_on_url('../base')
1229
1609
        reference_format = self.get_repo_format()
1230
1610
        network_name = reference_format.network_name()
1235
1615
            'success', ('branch', branch_network_name))
1236
1616
        client.add_expected_call(
1237
1617
            'BzrDir.find_repositoryV3', ('stacked/',),
1238
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1618
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1239
1619
        # called twice, once from constructor and then again by us
1240
1620
        client.add_expected_call(
1241
1621
            'Branch.get_stacked_on_url', ('stacked/',),
1244
1624
            'Branch.get_stacked_on_url', ('stacked/',),
1245
1625
            'success', ('ok', '../base'))
1246
1626
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1247
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1627
            RemoteBzrDirFormat(), _client=client)
1248
1628
        branch = bzrdir.open_branch()
1249
1629
        result = branch.get_stacked_on_url()
1250
1630
        self.assertEqual('../base', result)
1258
1638
class TestBranchSetLastRevision(RemoteBranchTestCase):
1259
1639
 
1260
1640
    def test_set_empty(self):
1261
 
        # set_revision_history([]) is translated to calling
 
1641
        # _set_last_revision_info('null:') is translated to calling
1262
1642
        # Branch.set_last_revision(path, '') on the wire.
1263
1643
        transport = MemoryTransport()
1264
1644
        transport.mkdir('branch')
1282
1662
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1283
1663
            'success', ('ok',))
1284
1664
        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
1665
        branch.lock_write()
1289
 
        result = branch.set_revision_history([])
 
1666
        result = branch._set_last_revision(NULL_REVISION)
1290
1667
        branch.unlock()
1291
1668
        self.assertEqual(None, result)
1292
1669
        self.assertFinished(client)
1293
1670
 
1294
1671
    def test_set_nonempty(self):
1295
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1672
        # set_last_revision_info(N, rev-idN) is translated to calling
1296
1673
        # Branch.set_last_revision(path, rev-idN) on the wire.
1297
1674
        transport = MemoryTransport()
1298
1675
        transport.mkdir('branch')
1319
1696
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1320
1697
            'success', ('ok',))
1321
1698
        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
1699
        # Lock the branch, reset the record of remote calls.
1326
1700
        branch.lock_write()
1327
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1701
        result = branch._set_last_revision('rev-id2')
1328
1702
        branch.unlock()
1329
1703
        self.assertEqual(None, result)
1330
1704
        self.assertFinished(client)
1360
1734
        branch = self.make_remote_branch(transport, client)
1361
1735
        branch.lock_write()
1362
1736
        self.assertRaises(
1363
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1737
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1364
1738
        branch.unlock()
1365
1739
        self.assertFinished(client)
1366
1740
 
1394
1768
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1395
1769
            'success', ('ok',))
1396
1770
        branch = self.make_remote_branch(transport, client)
1397
 
        branch._ensure_real = lambda: None
1398
1771
        branch.lock_write()
1399
1772
        # The 'TipChangeRejected' error response triggered by calling
1400
 
        # set_revision_history causes a TipChangeRejected exception.
 
1773
        # set_last_revision_info causes a TipChangeRejected exception.
1401
1774
        err = self.assertRaises(
1402
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1775
            errors.TipChangeRejected,
 
1776
            branch._set_last_revision, 'rev-id')
1403
1777
        # The UTF-8 message from the response has been decoded into a unicode
1404
1778
        # object.
1405
1779
        self.assertIsInstance(err.msg, unicode)
1593
1967
    def test_get_multi_line_branch_conf(self):
1594
1968
        # Make sure that multiple-line branch.conf files are supported
1595
1969
        #
1596
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1970
        # https://bugs.launchpad.net/bzr/+bug/354075
1597
1971
        client = FakeClient()
1598
1972
        client.add_expected_call(
1599
1973
            'Branch.get_stacked_on_url', ('memory:///',),
1627
2001
        branch.unlock()
1628
2002
        self.assertFinished(client)
1629
2003
 
 
2004
    def test_set_option_with_dict(self):
 
2005
        client = FakeClient()
 
2006
        client.add_expected_call(
 
2007
            'Branch.get_stacked_on_url', ('memory:///',),
 
2008
            'error', ('NotStacked',),)
 
2009
        client.add_expected_call(
 
2010
            'Branch.lock_write', ('memory:///', '', ''),
 
2011
            'success', ('ok', 'branch token', 'repo token'))
 
2012
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
2013
        client.add_expected_call(
 
2014
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
2015
            'repo token', encoded_dict_value, 'foo', ''),
 
2016
            'success', ())
 
2017
        client.add_expected_call(
 
2018
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2019
            'success', ('ok',))
 
2020
        transport = MemoryTransport()
 
2021
        branch = self.make_remote_branch(transport, client)
 
2022
        branch.lock_write()
 
2023
        config = branch._get_config()
 
2024
        config.set_option(
 
2025
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2026
            'foo')
 
2027
        branch.unlock()
 
2028
        self.assertFinished(client)
 
2029
 
1630
2030
    def test_backwards_compat_set_option(self):
1631
2031
        self.setup_smart_server_with_call_log()
1632
2032
        branch = self.make_branch('.')
1636
2036
        self.addCleanup(branch.unlock)
1637
2037
        self.reset_smart_call_log()
1638
2038
        branch._get_config().set_option('value', 'name')
1639
 
        self.assertLength(10, self.hpss_calls)
 
2039
        self.assertLength(11, self.hpss_calls)
1640
2040
        self.assertEqual('value', branch._get_config().get_option('name'))
1641
2041
 
 
2042
    def test_backwards_compat_set_option_with_dict(self):
 
2043
        self.setup_smart_server_with_call_log()
 
2044
        branch = self.make_branch('.')
 
2045
        verb = 'Branch.set_config_option_dict'
 
2046
        self.disable_verb(verb)
 
2047
        branch.lock_write()
 
2048
        self.addCleanup(branch.unlock)
 
2049
        self.reset_smart_call_log()
 
2050
        config = branch._get_config()
 
2051
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2052
        config.set_option(value_dict, 'name')
 
2053
        self.assertLength(11, self.hpss_calls)
 
2054
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2055
 
 
2056
 
 
2057
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2058
 
 
2059
    def test_get_branch_conf(self):
 
2060
        # in an empty branch we decode the response properly
 
2061
        client = FakeClient()
 
2062
        client.add_expected_call(
 
2063
            'Branch.get_stacked_on_url', ('memory:///',),
 
2064
            'error', ('NotStacked',),)
 
2065
        client.add_success_response_with_body('# config file body', 'ok')
 
2066
        transport = MemoryTransport()
 
2067
        branch = self.make_remote_branch(transport, client)
 
2068
        config = branch.get_config_stack()
 
2069
        config.get("email")
 
2070
        config.get("log_format")
 
2071
        self.assertEqual(
 
2072
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2073
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2074
            client._calls)
 
2075
 
 
2076
    def test_set_branch_conf(self):
 
2077
        client = FakeClient()
 
2078
        client.add_expected_call(
 
2079
            'Branch.get_stacked_on_url', ('memory:///',),
 
2080
            'error', ('NotStacked',),)
 
2081
        client.add_expected_call(
 
2082
            'Branch.lock_write', ('memory:///', '', ''),
 
2083
            'success', ('ok', 'branch token', 'repo token'))
 
2084
        client.add_expected_call(
 
2085
            'Branch.get_config_file', ('memory:///', ),
 
2086
            'success', ('ok', ), "# line 1\n")
 
2087
        client.add_expected_call(
 
2088
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2089
            'repo token'),
 
2090
            'success', ('ok',))
 
2091
        client.add_expected_call(
 
2092
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2093
            'success', ('ok',))
 
2094
        transport = MemoryTransport()
 
2095
        branch = self.make_remote_branch(transport, client)
 
2096
        branch.lock_write()
 
2097
        config = branch.get_config_stack()
 
2098
        config.set('email', 'The Dude <lebowski@example.com>')
 
2099
        branch.unlock()
 
2100
        self.assertFinished(client)
 
2101
        self.assertEqual(
 
2102
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2103
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2104
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2105
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2106
                 ('memory:///', 'branch token', 'repo token'),
 
2107
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2108
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2109
            client._calls)
 
2110
 
1642
2111
 
1643
2112
class TestBranchLockWrite(RemoteBranchTestCase):
1644
2113
 
1658
2127
        self.assertFinished(client)
1659
2128
 
1660
2129
 
 
2130
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2131
 
 
2132
    def test_simple(self):
 
2133
        transport = MemoryTransport()
 
2134
        client = FakeClient(transport.base)
 
2135
        client.add_expected_call(
 
2136
            'Branch.get_stacked_on_url', ('quack/',),
 
2137
            'error', ('NotStacked',),)
 
2138
        client.add_expected_call(
 
2139
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2140
            'success', ('ok', '0',),)
 
2141
        client.add_expected_call(
 
2142
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2143
            'error', ('NoSuchRevision', 'unknown',),)
 
2144
        transport.mkdir('quack')
 
2145
        transport = transport.clone('quack')
 
2146
        branch = self.make_remote_branch(transport, client)
 
2147
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2148
        self.assertRaises(errors.NoSuchRevision,
 
2149
            branch.revision_id_to_revno, 'unknown')
 
2150
        self.assertFinished(client)
 
2151
 
 
2152
    def test_dotted(self):
 
2153
        transport = MemoryTransport()
 
2154
        client = FakeClient(transport.base)
 
2155
        client.add_expected_call(
 
2156
            'Branch.get_stacked_on_url', ('quack/',),
 
2157
            'error', ('NotStacked',),)
 
2158
        client.add_expected_call(
 
2159
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2160
            'success', ('ok', '0',),)
 
2161
        client.add_expected_call(
 
2162
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2163
            'error', ('NoSuchRevision', 'unknown',),)
 
2164
        transport.mkdir('quack')
 
2165
        transport = transport.clone('quack')
 
2166
        branch = self.make_remote_branch(transport, client)
 
2167
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2168
        self.assertRaises(errors.NoSuchRevision,
 
2169
            branch.revision_id_to_dotted_revno, 'unknown')
 
2170
        self.assertFinished(client)
 
2171
 
 
2172
    def test_dotted_no_smart_verb(self):
 
2173
        self.setup_smart_server_with_call_log()
 
2174
        branch = self.make_branch('.')
 
2175
        self.disable_verb('Branch.revision_id_to_revno')
 
2176
        self.reset_smart_call_log()
 
2177
        self.assertEquals((0, ),
 
2178
            branch.revision_id_to_dotted_revno('null:'))
 
2179
        self.assertLength(8, self.hpss_calls)
 
2180
 
 
2181
 
1661
2182
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1662
2183
 
1663
2184
    def test__get_config(self):
1677
2198
        self.reset_smart_call_log()
1678
2199
        config = bzrdir.get_config()
1679
2200
        config.set_default_stack_on('/')
1680
 
        self.assertLength(3, self.hpss_calls)
 
2201
        self.assertLength(4, self.hpss_calls)
1681
2202
 
1682
2203
    def test_backwards_compat_get_option(self):
1683
2204
        self.setup_smart_server_with_call_log()
1687
2208
        self.reset_smart_call_log()
1688
2209
        self.assertEqual(None,
1689
2210
            bzrdir._get_config().get_option('default_stack_on'))
1690
 
        self.assertLength(3, self.hpss_calls)
 
2211
        self.assertLength(4, self.hpss_calls)
1691
2212
 
1692
2213
 
1693
2214
class TestTransportIsReadonly(tests.TestCase):
1780
2301
        client = FakeClient(transport.base)
1781
2302
        transport = transport.clone(transport_path)
1782
2303
        # we do not want bzrdir to make any remote calls
1783
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2304
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1784
2305
            _client=False)
1785
2306
        repo = RemoteRepository(bzrdir, None, _client=client)
1786
2307
        return repo, client
1794
2315
 
1795
2316
    def test_get_format_description(self):
1796
2317
        remote_format = RemoteBranchFormat()
1797
 
        real_format = branch.BranchFormat.get_default_format()
 
2318
        real_format = branch.format_registry.get_default()
1798
2319
        remote_format._network_name = real_format.network_name()
1799
2320
        self.assertEqual(remoted_description(real_format),
1800
2321
            remote_format.get_format_description())
1803
2324
class TestRepositoryFormat(TestRemoteRepository):
1804
2325
 
1805
2326
    def test_fast_delta(self):
1806
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2327
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1807
2328
        true_format = RemoteRepositoryFormat()
1808
2329
        true_format._network_name = true_name
1809
2330
        self.assertEqual(True, true_format.fast_deltas)
1810
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2331
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1811
2332
        false_format = RemoteRepositoryFormat()
1812
2333
        false_format._network_name = false_name
1813
2334
        self.assertEqual(False, false_format.fast_deltas)
1814
2335
 
1815
2336
    def test_get_format_description(self):
1816
2337
        remote_repo_format = RemoteRepositoryFormat()
1817
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2338
        real_format = repository.format_registry.get_default()
1818
2339
        remote_repo_format._network_name = real_format.network_name()
1819
2340
        self.assertEqual(remoted_description(real_format),
1820
2341
            remote_repo_format.get_format_description())
1821
2342
 
1822
2343
 
 
2344
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2345
 
 
2346
    def test_empty(self):
 
2347
        transport_path = 'quack'
 
2348
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2349
        client.add_success_response_with_body('', 'ok')
 
2350
        self.assertEquals([], repo.all_revision_ids())
 
2351
        self.assertEqual(
 
2352
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2353
             ('quack/',))],
 
2354
            client._calls)
 
2355
 
 
2356
    def test_with_some_content(self):
 
2357
        transport_path = 'quack'
 
2358
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2359
        client.add_success_response_with_body(
 
2360
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2361
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2362
            repo.all_revision_ids())
 
2363
        self.assertEqual(
 
2364
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2365
             ('quack/',))],
 
2366
            client._calls)
 
2367
 
 
2368
 
1823
2369
class TestRepositoryGatherStats(TestRemoteRepository):
1824
2370
 
1825
2371
    def test_revid_none(self):
1878
2424
                         result)
1879
2425
 
1880
2426
 
 
2427
class TestRepositoryBreakLock(TestRemoteRepository):
 
2428
 
 
2429
    def test_break_lock(self):
 
2430
        transport_path = 'quack'
 
2431
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2432
        client.add_success_response('ok')
 
2433
        repo.break_lock()
 
2434
        self.assertEqual(
 
2435
            [('call', 'Repository.break_lock', ('quack/',))],
 
2436
            client._calls)
 
2437
 
 
2438
 
 
2439
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2440
 
 
2441
    def test_get_serializer_format(self):
 
2442
        transport_path = 'hill'
 
2443
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2444
        client.add_success_response('ok', '7')
 
2445
        self.assertEquals('7', repo.get_serializer_format())
 
2446
        self.assertEqual(
 
2447
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2448
              ('hill/', ))],
 
2449
            client._calls)
 
2450
 
 
2451
 
 
2452
class TestRepositoryReconcile(TestRemoteRepository):
 
2453
 
 
2454
    def test_reconcile(self):
 
2455
        transport_path = 'hill'
 
2456
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2457
        body = ("garbage_inventories: 2\n"
 
2458
                "inconsistent_parents: 3\n")
 
2459
        client.add_expected_call(
 
2460
            'Repository.lock_write', ('hill/', ''),
 
2461
            'success', ('ok', 'a token'))
 
2462
        client.add_success_response_with_body(body, 'ok')
 
2463
        reconciler = repo.reconcile()
 
2464
        self.assertEqual(
 
2465
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2466
             ('call_expecting_body', 'Repository.reconcile',
 
2467
                ('hill/', 'a token'))],
 
2468
            client._calls)
 
2469
        self.assertEquals(2, reconciler.garbage_inventories)
 
2470
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2471
 
 
2472
 
 
2473
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2474
 
 
2475
    def test_text(self):
 
2476
        # ('ok',), body with signature text
 
2477
        transport_path = 'quack'
 
2478
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2479
        client.add_success_response_with_body(
 
2480
            'THETEXT', 'ok')
 
2481
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2482
        self.assertEqual(
 
2483
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2484
             ('quack/', 'revid'))],
 
2485
            client._calls)
 
2486
 
 
2487
    def test_no_signature(self):
 
2488
        transport_path = 'quick'
 
2489
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2490
        client.add_error_response('nosuchrevision', 'unknown')
 
2491
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2492
                "unknown")
 
2493
        self.assertEqual(
 
2494
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2495
              ('quick/', 'unknown'))],
 
2496
            client._calls)
 
2497
 
 
2498
 
1881
2499
class TestRepositoryGetGraph(TestRemoteRepository):
1882
2500
 
1883
2501
    def test_get_graph(self):
1888
2506
        self.assertNotEqual(graph._parents_provider, repo)
1889
2507
 
1890
2508
 
 
2509
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2510
 
 
2511
    def test_add_signature_text(self):
 
2512
        transport_path = 'quack'
 
2513
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2514
        client.add_expected_call(
 
2515
            'Repository.lock_write', ('quack/', ''),
 
2516
            'success', ('ok', 'a token'))
 
2517
        client.add_expected_call(
 
2518
            'Repository.start_write_group', ('quack/', 'a token'),
 
2519
            'success', ('ok', ('token1', )))
 
2520
        client.add_expected_call(
 
2521
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2522
                'token1'),
 
2523
            'success', ('ok', ), None)
 
2524
        repo.lock_write()
 
2525
        repo.start_write_group()
 
2526
        self.assertIs(None,
 
2527
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2528
        self.assertEqual(
 
2529
            ('call_with_body_bytes_expecting_body',
 
2530
              'Repository.add_signature_text',
 
2531
                ('quack/', 'a token', 'rev1', 'token1'),
 
2532
              'every bloody emperor'),
 
2533
            client._calls[-1])
 
2534
 
 
2535
 
1891
2536
class TestRepositoryGetParentMap(TestRemoteRepository):
1892
2537
 
1893
2538
    def test_get_parent_map_caching(self):
1943
2588
        parents = repo.get_parent_map([rev_id])
1944
2589
        self.assertEqual(
1945
2590
            [('call_with_body_bytes_expecting_body',
1946
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1947
 
              rev_id), '\n\n0'),
 
2591
              'Repository.get_parent_map',
 
2592
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1948
2593
             ('disconnect medium',),
1949
2594
             ('call_expecting_body', 'Repository.get_revision_graph',
1950
2595
              ('quack/', ''))],
2070
2715
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2071
2716
        self.assertLength(0, self.hpss_calls)
2072
2717
 
 
2718
    def test_exposes_get_cached_parent_map(self):
 
2719
        """RemoteRepository exposes get_cached_parent_map from
 
2720
        _unstacked_provider
 
2721
        """
 
2722
        r1 = u'\u0e33'.encode('utf8')
 
2723
        r2 = u'\u0dab'.encode('utf8')
 
2724
        lines = [' '.join([r2, r1]), r1]
 
2725
        encoded_body = bz2.compress('\n'.join(lines))
 
2726
 
 
2727
        transport_path = 'quack'
 
2728
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2729
        client.add_success_response_with_body(encoded_body, 'ok')
 
2730
        repo.lock_read()
 
2731
        # get_cached_parent_map should *not* trigger an RPC
 
2732
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2733
        self.assertEqual([], client._calls)
 
2734
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2735
        self.assertEqual({r1: (NULL_REVISION,)},
 
2736
            repo.get_cached_parent_map([r1]))
 
2737
        self.assertEqual(
 
2738
            [('call_with_body_bytes_expecting_body',
 
2739
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2740
              '\n\n0')],
 
2741
            client._calls)
 
2742
        repo.unlock()
 
2743
 
2073
2744
 
2074
2745
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2075
2746
 
2090
2761
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2091
2762
 
2092
2763
 
 
2764
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2765
 
 
2766
    def test_hpss_missing_revision(self):
 
2767
        transport_path = 'quack'
 
2768
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2769
        client.add_success_response_with_body(
 
2770
            '', 'ok', '10')
 
2771
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2772
            ['somerev1', 'anotherrev2'])
 
2773
        self.assertEqual(
 
2774
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2775
             ('quack/', ), "somerev1\nanotherrev2")],
 
2776
            client._calls)
 
2777
 
 
2778
    def test_hpss_get_single_revision(self):
 
2779
        transport_path = 'quack'
 
2780
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2781
        somerev1 = Revision("somerev1")
 
2782
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2783
        somerev1.timestamp = 1321828927
 
2784
        somerev1.timezone = -60
 
2785
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2786
        somerev1.message = "Message"
 
2787
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2788
            somerev1))
 
2789
        # Split up body into two bits to make sure the zlib compression object
 
2790
        # gets data fed twice.
 
2791
        client.add_success_response_with_body(
 
2792
                [body[:10], body[10:]], 'ok', '10')
 
2793
        revs = repo.get_revisions(['somerev1'])
 
2794
        self.assertEquals(revs, [somerev1])
 
2795
        self.assertEqual(
 
2796
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2797
             ('quack/', ), "somerev1")],
 
2798
            client._calls)
 
2799
 
 
2800
 
2093
2801
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2094
2802
 
2095
2803
    def test_null_revision(self):
2191
2899
        """
2192
2900
        # Make a repo with a fallback repo, both using a FakeClient.
2193
2901
        format = remote.response_tuple_to_repo_format(
2194
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2902
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2195
2903
        repo, client = self.setup_fake_client_and_repository('quack')
2196
2904
        repo._format = format
2197
2905
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2198
2906
            'fallback')
2199
2907
        fallback_repo._client = client
 
2908
        fallback_repo._format = format
2200
2909
        repo.add_fallback_repository(fallback_repo)
2201
2910
        # First the client should ask the primary repo
2202
2911
        client.add_expected_call(
2231
2940
        self.setup_smart_server_with_call_log()
2232
2941
        tree = self.make_branch_and_memory_tree('.')
2233
2942
        tree.lock_write()
 
2943
        tree.add('')
2234
2944
        rev1 = tree.commit('First')
2235
2945
        rev2 = tree.commit('Second')
2236
2946
        tree.unlock()
2244
2954
                              call.call.method == verb])
2245
2955
 
2246
2956
 
 
2957
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2958
 
 
2959
    def test_has_signature_for_revision_id(self):
 
2960
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2961
        transport_path = 'quack'
 
2962
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2963
        client.add_success_response('yes')
 
2964
        result = repo.has_signature_for_revision_id('A')
 
2965
        self.assertEqual(
 
2966
            [('call', 'Repository.has_signature_for_revision_id',
 
2967
              ('quack/', 'A'))],
 
2968
            client._calls)
 
2969
        self.assertEqual(True, result)
 
2970
 
 
2971
    def test_is_not_shared(self):
 
2972
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2973
        transport_path = 'qwack'
 
2974
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2975
        client.add_success_response('no')
 
2976
        result = repo.has_signature_for_revision_id('A')
 
2977
        self.assertEqual(
 
2978
            [('call', 'Repository.has_signature_for_revision_id',
 
2979
              ('qwack/', 'A'))],
 
2980
            client._calls)
 
2981
        self.assertEqual(False, result)
 
2982
 
 
2983
 
 
2984
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2985
 
 
2986
    def test_get_physical_lock_status_yes(self):
 
2987
        transport_path = 'qwack'
 
2988
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2989
        client.add_success_response('yes')
 
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(True, result)
 
2996
 
 
2997
    def test_get_physical_lock_status_no(self):
 
2998
        transport_path = 'qwack'
 
2999
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3000
        client.add_success_response('no')
 
3001
        result = repo.get_physical_lock_status()
 
3002
        self.assertEqual(
 
3003
            [('call', 'Repository.get_physical_lock_status',
 
3004
              ('qwack/', ))],
 
3005
            client._calls)
 
3006
        self.assertEqual(False, result)
 
3007
 
 
3008
 
2247
3009
class TestRepositoryIsShared(TestRemoteRepository):
2248
3010
 
2249
3011
    def test_is_shared(self):
2269
3031
        self.assertEqual(False, result)
2270
3032
 
2271
3033
 
 
3034
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3035
 
 
3036
    def test_make_working_trees(self):
 
3037
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3038
        transport_path = 'quack'
 
3039
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3040
        client.add_success_response('yes')
 
3041
        result = repo.make_working_trees()
 
3042
        self.assertEqual(
 
3043
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3044
            client._calls)
 
3045
        self.assertEqual(True, result)
 
3046
 
 
3047
    def test_no_working_trees(self):
 
3048
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3049
        transport_path = 'qwack'
 
3050
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3051
        client.add_success_response('no')
 
3052
        result = repo.make_working_trees()
 
3053
        self.assertEqual(
 
3054
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3055
            client._calls)
 
3056
        self.assertEqual(False, result)
 
3057
 
 
3058
 
2272
3059
class TestRepositoryLockWrite(TestRemoteRepository):
2273
3060
 
2274
3061
    def test_lock_write(self):
2275
3062
        transport_path = 'quack'
2276
3063
        repo, client = self.setup_fake_client_and_repository(transport_path)
2277
3064
        client.add_success_response('ok', 'a token')
2278
 
        result = repo.lock_write()
 
3065
        token = repo.lock_write().repository_token
2279
3066
        self.assertEqual(
2280
3067
            [('call', 'Repository.lock_write', ('quack/', ''))],
2281
3068
            client._calls)
2282
 
        self.assertEqual('a token', result)
 
3069
        self.assertEqual('a token', token)
2283
3070
 
2284
3071
    def test_lock_write_already_locked(self):
2285
3072
        transport_path = 'quack'
2300
3087
            client._calls)
2301
3088
 
2302
3089
 
 
3090
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3091
 
 
3092
    def test_start_write_group(self):
 
3093
        transport_path = 'quack'
 
3094
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3095
        client.add_expected_call(
 
3096
            'Repository.lock_write', ('quack/', ''),
 
3097
            'success', ('ok', 'a token'))
 
3098
        client.add_expected_call(
 
3099
            'Repository.start_write_group', ('quack/', 'a token'),
 
3100
            'success', ('ok', ('token1', )))
 
3101
        repo.lock_write()
 
3102
        repo.start_write_group()
 
3103
 
 
3104
    def test_start_write_group_unsuspendable(self):
 
3105
        # Some repositories do not support suspending write
 
3106
        # groups. For those, fall back to the "real" repository.
 
3107
        transport_path = 'quack'
 
3108
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3109
        def stub_ensure_real():
 
3110
            client._calls.append(('_ensure_real',))
 
3111
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3112
        repo._ensure_real = stub_ensure_real
 
3113
        client.add_expected_call(
 
3114
            'Repository.lock_write', ('quack/', ''),
 
3115
            'success', ('ok', 'a token'))
 
3116
        client.add_expected_call(
 
3117
            'Repository.start_write_group', ('quack/', 'a token'),
 
3118
            'error', ('UnsuspendableWriteGroup',))
 
3119
        repo.lock_write()
 
3120
        repo.start_write_group()
 
3121
        self.assertEquals(client._calls[-2:], [ 
 
3122
            ('_ensure_real',),
 
3123
            ('start_write_group',)])
 
3124
 
 
3125
    def test_commit_write_group(self):
 
3126
        transport_path = 'quack'
 
3127
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3128
        client.add_expected_call(
 
3129
            'Repository.lock_write', ('quack/', ''),
 
3130
            'success', ('ok', 'a token'))
 
3131
        client.add_expected_call(
 
3132
            'Repository.start_write_group', ('quack/', 'a token'),
 
3133
            'success', ('ok', ['token1']))
 
3134
        client.add_expected_call(
 
3135
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3136
            'success', ('ok',))
 
3137
        repo.lock_write()
 
3138
        repo.start_write_group()
 
3139
        repo.commit_write_group()
 
3140
 
 
3141
    def test_abort_write_group(self):
 
3142
        transport_path = 'quack'
 
3143
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3144
        client.add_expected_call(
 
3145
            'Repository.lock_write', ('quack/', ''),
 
3146
            'success', ('ok', 'a token'))
 
3147
        client.add_expected_call(
 
3148
            'Repository.start_write_group', ('quack/', 'a token'),
 
3149
            'success', ('ok', ['token1']))
 
3150
        client.add_expected_call(
 
3151
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3152
            'success', ('ok',))
 
3153
        repo.lock_write()
 
3154
        repo.start_write_group()
 
3155
        repo.abort_write_group(False)
 
3156
 
 
3157
    def test_suspend_write_group(self):
 
3158
        transport_path = 'quack'
 
3159
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3160
        self.assertEquals([], repo.suspend_write_group())
 
3161
 
 
3162
    def test_resume_write_group(self):
 
3163
        transport_path = 'quack'
 
3164
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3165
        client.add_expected_call(
 
3166
            'Repository.lock_write', ('quack/', ''),
 
3167
            'success', ('ok', 'a token'))
 
3168
        client.add_expected_call(
 
3169
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3170
            'success', ('ok',))
 
3171
        repo.lock_write()
 
3172
        repo.resume_write_group(['token1'])
 
3173
 
 
3174
 
2303
3175
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2304
3176
 
2305
3177
    def test_backwards_compat(self):
2364
3236
        self.assertEqual([], client._calls)
2365
3237
 
2366
3238
 
 
3239
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3240
    """Test Repository.iter_file_bytes."""
 
3241
 
 
3242
    def test_single(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', ('quack/', ),
 
3247
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3248
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3249
                "somerev", "myid")]):
 
3250
            self.assertEquals("myid", identifier)
 
3251
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3252
 
 
3253
    def test_missing(self):
 
3254
        transport_path = 'quack'
 
3255
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3256
        client.add_expected_call(
 
3257
            'Repository.iter_files_bytes',
 
3258
                ('quack/', ),
 
3259
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3260
            iter(["absent\0somefile\0somerev\n"]))
 
3261
        self.assertRaises(errors.RevisionNotPresent, list,
 
3262
                repo.iter_files_bytes(
 
3263
                [("somefile", "somerev", "myid")]))
 
3264
 
 
3265
 
2367
3266
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2368
3267
    """Base class for Repository.insert_stream and .insert_stream_1.19
2369
3268
    tests.
2376
3275
        the client is finished.
2377
3276
        """
2378
3277
        sink = repo._get_sink()
2379
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3278
        fmt = repository.format_registry.get_default()
2380
3279
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2381
3280
        self.assertEqual([], resume_tokens)
2382
3281
        self.assertEqual(set(), missing_keys)
2482
3381
                return True
2483
3382
        repo._real_repository = FakeRealRepository()
2484
3383
        sink = repo._get_sink()
2485
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3384
        fmt = repository.format_registry.get_default()
2486
3385
        stream = self.make_stream_with_inv_deltas(fmt)
2487
3386
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2488
3387
        # Every record from the first inventory delta should have been sent to
2644
3543
        self.calls = calls
2645
3544
        self._pack_collection = _StubPackCollection(calls)
2646
3545
 
 
3546
    def start_write_group(self):
 
3547
        self.calls.append(('start_write_group',))
 
3548
 
2647
3549
    def is_in_write_group(self):
2648
3550
        return False
2649
3551
 
2708
3610
             ('pack collection autopack',)],
2709
3611
            client._calls)
2710
3612
 
 
3613
    def test_oom_error_reporting(self):
 
3614
        """An out-of-memory condition on the server is reported clearly"""
 
3615
        transport_path = 'quack'
 
3616
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3617
        client.add_expected_call(
 
3618
            'PackRepository.autopack', ('quack/',),
 
3619
            'error', ('MemoryError',))
 
3620
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3621
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3622
 
2711
3623
 
2712
3624
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2713
3625
    """Base class for unit tests for bzrlib.remote._translate_error."""
2786
3698
            detail='extra detail')
2787
3699
        self.assertEqual(expected_error, translated_error)
2788
3700
 
 
3701
    def test_norepository(self):
 
3702
        bzrdir = self.make_bzrdir('')
 
3703
        translated_error = self.translateTuple(('norepository',),
 
3704
            bzrdir=bzrdir)
 
3705
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3706
        self.assertEqual(expected_error, translated_error)
 
3707
 
2789
3708
    def test_LockContention(self):
2790
3709
        translated_error = self.translateTuple(('LockContention',))
2791
3710
        expected_error = errors.LockContention('(remote lock)')
2819
3738
        expected_error = errors.DivergedBranches(branch, other_branch)
2820
3739
        self.assertEqual(expected_error, translated_error)
2821
3740
 
 
3741
    def test_NotStacked(self):
 
3742
        branch = self.make_branch('')
 
3743
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3744
        expected_error = errors.NotStacked(branch)
 
3745
        self.assertEqual(expected_error, translated_error)
 
3746
 
2822
3747
    def test_ReadError_no_args(self):
2823
3748
        path = 'a path'
2824
3749
        translated_error = self.translateTuple(('ReadError',), path=path)
2840
3765
 
2841
3766
    def test_PermissionDenied_no_args(self):
2842
3767
        path = 'a path'
2843
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3768
        translated_error = self.translateTuple(('PermissionDenied',),
 
3769
            path=path)
2844
3770
        expected_error = errors.PermissionDenied(path)
2845
3771
        self.assertEqual(expected_error, translated_error)
2846
3772
 
2869
3795
        expected_error = errors.PermissionDenied(path, extra)
2870
3796
        self.assertEqual(expected_error, translated_error)
2871
3797
 
 
3798
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3799
 
 
3800
    def test_NoSuchFile_context_path(self):
 
3801
        local_path = "local path"
 
3802
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3803
            path=local_path)
 
3804
        expected_error = errors.ReadError(local_path)
 
3805
        self.assertEqual(expected_error, translated_error)
 
3806
 
 
3807
    def test_NoSuchFile_without_context(self):
 
3808
        remote_path = "remote path"
 
3809
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3810
        expected_error = errors.ReadError(remote_path)
 
3811
        self.assertEqual(expected_error, translated_error)
 
3812
 
 
3813
    def test_ReadOnlyError(self):
 
3814
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3815
        expected_error = errors.TransportNotPossible("readonly transport")
 
3816
        self.assertEqual(expected_error, translated_error)
 
3817
 
 
3818
    def test_MemoryError(self):
 
3819
        translated_error = self.translateTuple(('MemoryError',))
 
3820
        self.assertStartsWith(str(translated_error),
 
3821
            "remote server out of memory")
 
3822
 
 
3823
    def test_generic_IndexError_no_classname(self):
 
3824
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3825
        translated_error = self.translateErrorFromSmartServer(err)
 
3826
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3827
        self.assertEqual(expected_error, translated_error)
 
3828
 
 
3829
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3830
 
 
3831
    def test_generic_KeyError(self):
 
3832
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3833
        translated_error = self.translateErrorFromSmartServer(err)
 
3834
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3835
        self.assertEqual(expected_error, translated_error)
 
3836
 
2872
3837
 
2873
3838
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2874
3839
    """Unit tests for bzrlib.remote._translate_error's robustness.
3019
3984
        _, stacked = branch_factory()
3020
3985
        source = stacked.repository._get_source(target_repository_format)
3021
3986
        tip = stacked.last_revision()
3022
 
        revs = stacked.repository.get_ancestry(tip)
3023
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3987
        stacked.repository._ensure_real()
 
3988
        graph = stacked.repository.get_graph()
 
3989
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3990
                if r != NULL_REVISION]
 
3991
        revs.reverse()
 
3992
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3024
3993
        self.reset_smart_call_log()
3025
3994
        stream = source.get_stream(search)
3026
 
        if None in revs:
3027
 
            revs.remove(None)
3028
3995
        # We trust that if a revision is in the stream the rest of the new
3029
3996
        # content for it is too, as per our main fetch tests; here we are
3030
3997
        # checking that the revisions are actually included at all, and their
3069
4036
        self.assertEqual(expected_revs, rev_ord)
3070
4037
        # Getting topological sort requires VFS calls still - one of which is
3071
4038
        # pushing up from the bound branch.
3072
 
        self.assertLength(13, self.hpss_calls)
 
4039
        self.assertLength(14, self.hpss_calls)
3073
4040
 
3074
4041
    def test_stacked_get_stream_groupcompress(self):
3075
4042
        # Repository._get_source.get_stream() from a stacked repository with
3116
4083
 
3117
4084
    def test_copy_content_into_avoids_revision_history(self):
3118
4085
        local = self.make_branch('local')
3119
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3120
 
        remote_backing_tree.commit("Commit.")
 
4086
        builder = self.make_branch_builder('remote')
 
4087
        builder.build_commit(message="Commit.")
3121
4088
        remote_branch_url = self.smart_server.get_url() + 'remote'
3122
4089
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3123
4090
        local.repository.fetch(remote_branch.repository)
3124
4091
        self.hpss_calls = []
3125
4092
        remote_branch.copy_content_into(local)
3126
4093
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4094
 
 
4095
    def test_fetch_everything_needs_just_one_call(self):
 
4096
        local = self.make_branch('local')
 
4097
        builder = self.make_branch_builder('remote')
 
4098
        builder.build_commit(message="Commit.")
 
4099
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4100
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4101
        self.hpss_calls = []
 
4102
        local.repository.fetch(
 
4103
            remote_branch.repository,
 
4104
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4105
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4106
 
 
4107
    def override_verb(self, verb_name, verb):
 
4108
        request_handlers = request.request_handlers
 
4109
        orig_verb = request_handlers.get(verb_name)
 
4110
        orig_info = request_handlers.get_info(verb_name)
 
4111
        request_handlers.register(verb_name, verb, override_existing=True)
 
4112
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4113
                override_existing=True, info=orig_info)
 
4114
 
 
4115
    def test_fetch_everything_backwards_compat(self):
 
4116
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4117
        
 
4118
        Pre-2.4 do not support 'everything' searches with the
 
4119
        Repository.get_stream_1.19 verb.
 
4120
        """
 
4121
        verb_log = []
 
4122
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4123
            """A version of the Repository.get_stream_1.19 verb patched to
 
4124
            reject 'everything' searches the way 2.3 and earlier do.
 
4125
            """
 
4126
            def recreate_search(self, repository, search_bytes,
 
4127
                                discard_excess=False):
 
4128
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4129
                if search_bytes == 'everything':
 
4130
                    return (None,
 
4131
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4132
                return super(OldGetStreamVerb,
 
4133
                        self).recreate_search(repository, search_bytes,
 
4134
                            discard_excess=discard_excess)
 
4135
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4136
        local = self.make_branch('local')
 
4137
        builder = self.make_branch_builder('remote')
 
4138
        builder.build_commit(message="Commit.")
 
4139
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4140
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4141
        self.hpss_calls = []
 
4142
        local.repository.fetch(
 
4143
            remote_branch.repository,
 
4144
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4145
        # make sure the overridden verb was used
 
4146
        self.assertLength(1, verb_log)
 
4147
        # more than one HPSS call is needed, but because it's a VFS callback
 
4148
        # its hard to predict exactly how many.
 
4149
        self.assertTrue(len(self.hpss_calls) > 1)
 
4150
 
 
4151
 
 
4152
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4153
    tests.TestCaseWithTransport):
 
4154
    """Ensure correct handling of bound_location modifications.
 
4155
 
 
4156
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4157
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4158
    happen in this context.
 
4159
    """
 
4160
 
 
4161
    def setUp(self):
 
4162
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4163
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4164
 
 
4165
    def make_master_and_checkout(self, master_name, checkout_name):
 
4166
        # Create the master branch and its associated checkout
 
4167
        self.master = self.make_branch_and_tree(master_name)
 
4168
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4169
        # Modify the master branch so there is something to update
 
4170
        self.master.commit('add stuff')
 
4171
        self.last_revid = self.master.commit('even more stuff')
 
4172
        self.bound_location = self.checkout.branch.get_bound_location()
 
4173
 
 
4174
    def assertUpdateSucceeds(self, new_location):
 
4175
        self.checkout.branch.set_bound_location(new_location)
 
4176
        self.checkout.update()
 
4177
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4178
 
 
4179
    def test_without_final_slash(self):
 
4180
        self.make_master_and_checkout('master', 'checkout')
 
4181
        # For unclear reasons some users have a bound_location without a final
 
4182
        # '/', simulate that by forcing such a value
 
4183
        self.assertEndsWith(self.bound_location, '/')
 
4184
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4185
 
 
4186
    def test_plus_sign(self):
 
4187
        self.make_master_and_checkout('+master', 'checkout')
 
4188
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4189
 
 
4190
    def test_tilda(self):
 
4191
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4192
        # interpretation
 
4193
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4194
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4195
 
 
4196
 
 
4197
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4198
 
 
4199
    def test_no_context(self):
 
4200
        class OutOfCoffee(errors.BzrError):
 
4201
            """A dummy exception for testing."""
 
4202
 
 
4203
            def __init__(self, urgency):
 
4204
                self.urgency = urgency
 
4205
        remote.no_context_error_translators.register("OutOfCoffee",
 
4206
            lambda err: OutOfCoffee(err.error_args[0]))
 
4207
        transport = MemoryTransport()
 
4208
        client = FakeClient(transport.base)
 
4209
        client.add_expected_call(
 
4210
            'Branch.get_stacked_on_url', ('quack/',),
 
4211
            'error', ('NotStacked',))
 
4212
        client.add_expected_call(
 
4213
            'Branch.last_revision_info',
 
4214
            ('quack/',),
 
4215
            'error', ('OutOfCoffee', 'low'))
 
4216
        transport.mkdir('quack')
 
4217
        transport = transport.clone('quack')
 
4218
        branch = self.make_remote_branch(transport, client)
 
4219
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4220
        self.assertFinished(client)
 
4221
 
 
4222
    def test_with_context(self):
 
4223
        class OutOfTea(errors.BzrError):
 
4224
            def __init__(self, branch, urgency):
 
4225
                self.branch = branch
 
4226
                self.urgency = urgency
 
4227
        remote.error_translators.register("OutOfTea",
 
4228
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4229
                find("branch")))
 
4230
        transport = MemoryTransport()
 
4231
        client = FakeClient(transport.base)
 
4232
        client.add_expected_call(
 
4233
            'Branch.get_stacked_on_url', ('quack/',),
 
4234
            'error', ('NotStacked',))
 
4235
        client.add_expected_call(
 
4236
            'Branch.last_revision_info',
 
4237
            ('quack/',),
 
4238
            'error', ('OutOfTea', 'low'))
 
4239
        transport.mkdir('quack')
 
4240
        transport = transport.clone('quack')
 
4241
        branch = self.make_remote_branch(transport, client)
 
4242
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4243
        self.assertFinished(client)
 
4244
 
 
4245
 
 
4246
class TestRepositoryPack(TestRemoteRepository):
 
4247
 
 
4248
    def test_pack(self):
 
4249
        transport_path = 'quack'
 
4250
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4251
        client.add_expected_call(
 
4252
            'Repository.lock_write', ('quack/', ''),
 
4253
            'success', ('ok', 'token'))
 
4254
        client.add_expected_call(
 
4255
            'Repository.pack', ('quack/', 'token', 'False'),
 
4256
            'success', ('ok',), )
 
4257
        client.add_expected_call(
 
4258
            'Repository.unlock', ('quack/', 'token'),
 
4259
            'success', ('ok', ))
 
4260
        repo.pack()
 
4261
 
 
4262
    def test_pack_with_hint(self):
 
4263
        transport_path = 'quack'
 
4264
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4265
        client.add_expected_call(
 
4266
            'Repository.lock_write', ('quack/', ''),
 
4267
            'success', ('ok', 'token'))
 
4268
        client.add_expected_call(
 
4269
            'Repository.pack', ('quack/', 'token', 'False'),
 
4270
            'success', ('ok',), )
 
4271
        client.add_expected_call(
 
4272
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4273
            'success', ('ok', ))
 
4274
        repo.pack(['hinta', 'hintb'])
 
4275
 
 
4276
 
 
4277
class TestRepositoryIterInventories(TestRemoteRepository):
 
4278
    """Test Repository.iter_inventories."""
 
4279
 
 
4280
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4281
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4282
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4283
 
 
4284
    def test_single_empty(self):
 
4285
        transport_path = 'quack'
 
4286
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4287
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4288
        repo._format = fmt
 
4289
        stream = [('inventory-deltas', [
 
4290
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4291
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4292
        client.add_expected_call(
 
4293
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4294
            'success', ('ok', ),
 
4295
            _stream_to_byte_stream(stream, fmt))
 
4296
        ret = list(repo.iter_inventories(["somerevid"]))
 
4297
        self.assertLength(1, ret)
 
4298
        inv = ret[0]
 
4299
        self.assertEquals("somerevid", inv.revision_id)
 
4300
 
 
4301
    def test_empty(self):
 
4302
        transport_path = 'quack'
 
4303
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4304
        ret = list(repo.iter_inventories([]))
 
4305
        self.assertEquals(ret, [])
 
4306
 
 
4307
    def test_missing(self):
 
4308
        transport_path = 'quack'
 
4309
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4310
        client.add_expected_call(
 
4311
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4312
            'success', ('ok', ), iter([]))
 
4313
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4314
            ["somerevid"]))