~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

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 (
30
31
    branch,
31
32
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    graph as _mod_graph,
35
37
    inventory,
36
38
    inventory_delta,
37
 
    pack,
38
39
    remote,
39
40
    repository,
40
41
    tests,
 
42
    transport,
41
43
    treebuilder,
42
 
    urlutils,
43
44
    versionedfile,
 
45
    vf_search,
44
46
    )
45
47
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
48
from bzrlib.bzrdir import (
 
49
    BzrDir,
 
50
    BzrDirFormat,
 
51
    RemoteBzrProber,
 
52
    )
 
53
from bzrlib.chk_serializer import chk_bencode_serializer
47
54
from bzrlib.remote import (
48
55
    RemoteBranch,
49
56
    RemoteBranchFormat,
52
59
    RemoteRepository,
53
60
    RemoteRepositoryFormat,
54
61
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import server, 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,
 
76
    test_server,
64
77
    )
65
 
from bzrlib.transport import get_transport
 
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
66
79
from bzrlib.transport.memory import MemoryTransport
67
80
from bzrlib.transport.remote import (
68
81
    RemoteTransport,
69
82
    RemoteSSHTransport,
70
83
    RemoteTCPTransport,
71
 
)
72
 
 
73
 
def load_tests(standard_tests, module, loader):
74
 
    to_adapt, result = split_suite_by_condition(
75
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
76
 
    smart_server_version_scenarios = [
 
84
    )
 
85
 
 
86
 
 
87
load_tests = load_tests_apply_scenarios
 
88
 
 
89
 
 
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
91
 
 
92
    scenarios = [
77
93
        ('HPSS-v2',
78
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
 
94
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
79
95
        ('HPSS-v3',
80
 
            {'transport_server': server.SmartTCPServer_for_testing})]
81
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
82
 
 
83
 
 
84
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
96
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
97
 
85
98
 
86
99
    def setUp(self):
87
100
        super(BasicRemoteObjectTests, self).setUp()
88
101
        self.transport = self.get_transport()
89
102
        # make a branch that can be opened over the smart transport
90
103
        self.local_wt = BzrDir.create_standalone_workingtree('.')
91
 
 
92
 
    def tearDown(self):
93
 
        self.transport.disconnect()
94
 
        tests.TestCaseWithTransport.tearDown(self)
 
104
        self.addCleanup(self.transport.disconnect)
95
105
 
96
106
    def test_create_remote_bzrdir(self):
97
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
107
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
98
108
        self.assertIsInstance(b, BzrDir)
99
109
 
100
110
    def test_open_remote_branch(self):
101
111
        # open a standalone branch in the working directory
102
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
112
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
103
113
        branch = b.open_branch()
104
114
        self.assertIsInstance(branch, Branch)
105
115
 
113
123
 
114
124
    def test_remote_branch_revision_history(self):
115
125
        b = BzrDir.open_from_transport(self.transport).open_branch()
116
 
        self.assertEqual([], b.revision_history())
 
126
        self.assertEqual([],
 
127
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
117
128
        r1 = self.local_wt.commit('1st commit')
118
129
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
119
 
        self.assertEqual([r1, r2], b.revision_history())
 
130
        self.assertEqual([r1, r2],
 
131
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
120
132
 
121
133
    def test_find_correct_format(self):
122
134
        """Should open a RemoteBzrDir over a RemoteTransport"""
123
135
        fmt = BzrDirFormat.find_format(self.transport)
124
 
        self.assertTrue(RemoteBzrDirFormat
125
 
                        in BzrDirFormat._control_server_formats)
126
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
136
        self.assertTrue(bzrdir.RemoteBzrProber
 
137
                        in controldir.ControlDirFormat._server_probers)
 
138
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
127
139
 
128
140
    def test_open_detected_smart_format(self):
129
141
        fmt = BzrDirFormat.find_format(self.transport)
134
146
        b = BzrDir.open_from_transport(self.transport).open_branch()
135
147
        self.assertStartsWith(str(b), 'RemoteBranch(')
136
148
 
 
149
    def test_remote_bzrdir_repr(self):
 
150
        b = BzrDir.open_from_transport(self.transport)
 
151
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
 
152
 
137
153
    def test_remote_branch_format_supports_stacking(self):
138
154
        t = self.transport
139
155
        self.make_branch('unstackable', format='pack-0.92')
159
175
    def test_remote_branch_set_append_revisions_only(self):
160
176
        # Make a format 1.9 branch, which supports append_revisions_only
161
177
        branch = self.make_branch('branch', format='1.9')
162
 
        config = branch.get_config()
163
178
        branch.set_append_revisions_only(True)
 
179
        config = branch.get_config_stack()
164
180
        self.assertEqual(
165
 
            'True', config.get_user_option('append_revisions_only'))
 
181
            True, config.get('append_revisions_only'))
166
182
        branch.set_append_revisions_only(False)
 
183
        config = branch.get_config_stack()
167
184
        self.assertEqual(
168
 
            'False', config.get_user_option('append_revisions_only'))
 
185
            False, config.get('append_revisions_only'))
169
186
 
170
187
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
171
188
        branch = self.make_branch('branch', format='knit')
172
 
        config = branch.get_config()
173
189
        self.assertRaises(
174
190
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
175
191
 
354
370
        a given client_base and transport_base.
355
371
        """
356
372
        client_medium = medium.SmartClientMedium(client_base)
357
 
        transport = get_transport(transport_base)
358
 
        result = client_medium.remote_path_from_transport(transport)
 
373
        t = transport.get_transport(transport_base)
 
374
        result = client_medium.remote_path_from_transport(t)
359
375
        self.assertEqual(expected, result)
360
376
 
361
377
    def test_remote_path_from_transport(self):
372
388
        a given transport_base and relpath of that transport.  (Note that
373
389
        HttpTransportBase is a subclass of SmartClientMedium)
374
390
        """
375
 
        base_transport = get_transport(transport_base)
 
391
        base_transport = transport.get_transport(transport_base)
376
392
        client_medium = base_transport.get_smart_medium()
377
393
        cloned_transport = base_transport.clone(relpath)
378
394
        result = client_medium.remote_path_from_transport(cloned_transport)
413
429
        # Calling _remember_remote_is_before again with a lower value works.
414
430
        client_medium._remember_remote_is_before((1, 5))
415
431
        self.assertTrue(client_medium._is_remote_before((1, 5)))
416
 
        # You cannot call _remember_remote_is_before with a larger value.
417
 
        self.assertRaises(
418
 
            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)))
419
438
 
420
439
 
421
440
class TestBzrDirCloningMetaDir(TestRemote):
440
459
            'BzrDir.cloning_metadir', ('quack/', 'False'),
441
460
            'error', ('BranchReference',)),
442
461
        client.add_expected_call(
443
 
            'BzrDir.open_branchV2', ('quack/',),
 
462
            'BzrDir.open_branchV3', ('quack/',),
444
463
            'success', ('ref', self.get_url('referenced'))),
445
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
464
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
446
465
            _client=client)
447
466
        result = a_bzrdir.cloning_metadir()
448
467
        # We should have got a control dir matching the referenced branch.
461
480
        client.add_expected_call(
462
481
            'BzrDir.cloning_metadir', ('quack/', 'False'),
463
482
            'success', (control_name, '', ('branch', ''))),
464
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
483
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
465
484
            _client=client)
466
485
        result = a_bzrdir.cloning_metadir()
467
486
        # We should have got a reference control dir with default branch and
472
491
        self.assertEqual(None, result._branch_format)
473
492
        self.assertFinished(client)
474
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 TestBzrDirDestroyBranch(TestRemote):
 
545
 
 
546
    def test_destroy_default(self):
 
547
        transport = self.get_transport('quack')
 
548
        referenced = self.make_branch('referenced')
 
549
        client = FakeClient(transport.base)
 
550
        client.add_expected_call(
 
551
            'BzrDir.destroy_branch', ('quack/', ),
 
552
            'success', ('ok',)),
 
553
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
554
            _client=client)
 
555
        a_bzrdir.destroy_branch()
 
556
        self.assertFinished(client)
 
557
 
 
558
    def test_destroy_named(self):
 
559
        transport = self.get_transport('quack')
 
560
        referenced = self.make_branch('referenced')
 
561
        client = FakeClient(transport.base)
 
562
        client.add_expected_call(
 
563
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
564
            'success', ('ok',)),
 
565
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
566
            _client=client)
 
567
        a_bzrdir.destroy_branch("foo")
 
568
        self.assertFinished(client)
 
569
 
 
570
 
 
571
class TestBzrDirHasWorkingTree(TestRemote):
 
572
 
 
573
    def test_has_workingtree(self):
 
574
        transport = self.get_transport('quack')
 
575
        client = FakeClient(transport.base)
 
576
        client.add_expected_call(
 
577
            'BzrDir.has_workingtree', ('quack/',),
 
578
            'success', ('yes',)),
 
579
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
580
            _client=client)
 
581
        self.assertTrue(a_bzrdir.has_workingtree())
 
582
        self.assertFinished(client)
 
583
 
 
584
    def test_no_workingtree(self):
 
585
        transport = self.get_transport('quack')
 
586
        client = FakeClient(transport.base)
 
587
        client.add_expected_call(
 
588
            'BzrDir.has_workingtree', ('quack/',),
 
589
            'success', ('no',)),
 
590
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
591
            _client=client)
 
592
        self.assertFalse(a_bzrdir.has_workingtree())
 
593
        self.assertFinished(client)
 
594
 
 
595
 
 
596
class TestBzrDirDestroyRepository(TestRemote):
 
597
 
 
598
    def test_destroy_repository(self):
 
599
        transport = self.get_transport('quack')
 
600
        client = FakeClient(transport.base)
 
601
        client.add_expected_call(
 
602
            'BzrDir.destroy_repository', ('quack/',),
 
603
            'success', ('ok',)),
 
604
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
605
            _client=client)
 
606
        a_bzrdir.destroy_repository()
 
607
        self.assertFinished(client)
 
608
 
475
609
 
476
610
class TestBzrDirOpen(TestRemote):
477
611
 
487
621
        client.add_expected_call(
488
622
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
489
623
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
490
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
624
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
491
625
        self.assertFinished(client)
492
626
 
493
627
    def test_present_without_workingtree(self):
494
628
        client, transport = self.make_fake_client_and_transport()
495
629
        client.add_expected_call(
496
630
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
497
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
631
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
498
632
            _client=client, _force_probe=True)
499
633
        self.assertIsInstance(bd, RemoteBzrDir)
500
634
        self.assertFalse(bd.has_workingtree())
505
639
        client, transport = self.make_fake_client_and_transport()
506
640
        client.add_expected_call(
507
641
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
508
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
642
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
509
643
            _client=client, _force_probe=True)
510
644
        self.assertIsInstance(bd, RemoteBzrDir)
511
645
        self.assertTrue(bd.has_workingtree())
518
652
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
519
653
        client.add_expected_call(
520
654
            'BzrDir.open', ('quack/',), 'success', ('yes',))
521
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
655
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
656
            _client=client, _force_probe=True)
 
657
        self.assertIsInstance(bd, RemoteBzrDir)
 
658
        self.assertFinished(client)
 
659
 
 
660
    def test_backwards_compat_hpss_v2(self):
 
661
        client, transport = self.make_fake_client_and_transport()
 
662
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
663
        # server: upon first RPC call detect the protocol version, and because
 
664
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
665
        # continuing with the RPC.
 
666
        orig_check_call = client._check_call
 
667
        def check_call(method, args):
 
668
            client._medium._protocol_version = 2
 
669
            client._medium._remember_remote_is_before((1, 6))
 
670
            client._check_call = orig_check_call
 
671
            client._check_call(method, args)
 
672
        client._check_call = check_call
 
673
        client.add_expected_call(
 
674
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
675
        client.add_expected_call(
 
676
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
677
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
522
678
            _client=client, _force_probe=True)
523
679
        self.assertIsInstance(bd, RemoteBzrDir)
524
680
        self.assertFinished(client)
531
687
        self.make_branch('.')
532
688
        a_dir = BzrDir.open(self.get_url('.'))
533
689
        self.reset_smart_call_log()
534
 
        verb = 'BzrDir.open_branchV2'
 
690
        verb = 'BzrDir.open_branchV3'
535
691
        self.disable_verb(verb)
536
692
        format = a_dir.open_branch()
537
693
        call_count = len([call for call in self.hpss_calls if
547
703
        transport = transport.clone('quack')
548
704
        client = FakeClient(transport.base)
549
705
        client.add_expected_call(
550
 
            'BzrDir.open_branchV2', ('quack/',),
 
706
            'BzrDir.open_branchV3', ('quack/',),
551
707
            'success', ('branch', branch_network_name))
552
708
        client.add_expected_call(
553
709
            'BzrDir.find_repositoryV3', ('quack/',),
555
711
        client.add_expected_call(
556
712
            'Branch.get_stacked_on_url', ('quack/',),
557
713
            'error', ('NotStacked',))
558
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
714
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
559
715
            _client=client)
560
716
        result = bzrdir.open_branch()
561
717
        self.assertIsInstance(result, RemoteBranch)
568
724
        transport = transport.clone('quack')
569
725
        client = FakeClient(transport.base)
570
726
        client.add_error_response('nobranch')
571
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
727
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
572
728
            _client=client)
573
729
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
574
730
        self.assertEqual(
575
 
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
 
731
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
576
732
            client._calls)
577
733
 
578
734
    def test__get_tree_branch(self):
579
735
        # _get_tree_branch is a form of open_branch, but it should only ask for
580
736
        # branch opening, not any other network requests.
581
737
        calls = []
582
 
        def open_branch():
 
738
        def open_branch(name=None, possible_transports=None):
583
739
            calls.append("Called")
584
740
            return "a-branch"
585
741
        transport = MemoryTransport()
586
742
        # no requests on the network - catches other api calls being made.
587
743
        client = FakeClient(transport.base)
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
744
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
745
            _client=client)
590
746
        # patch the open_branch call to record that it was called.
591
747
        bzrdir.open_branch = open_branch
602
758
        network_name = reference_format.network_name()
603
759
        branch_network_name = self.get_branch_format().network_name()
604
760
        client.add_expected_call(
605
 
            'BzrDir.open_branchV2', ('~hello/',),
 
761
            'BzrDir.open_branchV3', ('~hello/',),
606
762
            'success', ('branch', branch_network_name))
607
763
        client.add_expected_call(
608
764
            'BzrDir.find_repositoryV3', ('~hello/',),
610
766
        client.add_expected_call(
611
767
            'Branch.get_stacked_on_url', ('~hello/',),
612
768
            'error', ('NotStacked',))
613
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
769
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
614
770
            _client=client)
615
771
        result = bzrdir.open_branch()
616
772
        self.assertFinished(client)
633
789
        client.add_success_response(
634
790
            'ok', '', rich_response, subtree_response, external_lookup,
635
791
            network_name)
636
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
792
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
637
793
            _client=client)
638
794
        result = bzrdir.open_repository()
639
795
        self.assertEqual(
656
812
        old.
657
813
        """
658
814
        self.assertRaises(errors.NotBranchError,
659
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
815
            RemoteBzrProber.probe_transport, OldServerTransport())
660
816
 
661
817
 
662
818
class TestBzrDirCreateBranch(TestRemote):
685
841
            'BzrDir.create_branch', ('quack/', network_name),
686
842
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
687
843
            reference_repo_name))
688
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
844
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
689
845
            _client=client)
690
846
        branch = a_bzrdir.create_branch()
691
847
        # We should have got a remote branch
694
850
        format = branch._format
695
851
        self.assertEqual(network_name, format.network_name())
696
852
 
 
853
    def test_already_open_repo_and_reused_medium(self):
 
854
        """Bug 726584: create_branch(..., repository=repo) should work
 
855
        regardless of what the smart medium's base URL is.
 
856
        """
 
857
        self.transport_server = test_server.SmartTCPServer_for_testing
 
858
        transport = self.get_transport('.')
 
859
        repo = self.make_repository('quack')
 
860
        # Client's medium rooted a transport root (not at the bzrdir)
 
861
        client = FakeClient(transport.base)
 
862
        transport = transport.clone('quack')
 
863
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
864
        reference_format = reference_bzrdir_format.get_branch_format()
 
865
        network_name = reference_format.network_name()
 
866
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
867
        reference_repo_name = reference_repo_fmt.network_name()
 
868
        client.add_expected_call(
 
869
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
870
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
871
            reference_repo_name))
 
872
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
873
            _client=client)
 
874
        branch = a_bzrdir.create_branch(repository=repo)
 
875
        # We should have got a remote branch
 
876
        self.assertIsInstance(branch, remote.RemoteBranch)
 
877
        # its format should have the settings from the response
 
878
        format = branch._format
 
879
        self.assertEqual(network_name, format.network_name())
 
880
 
697
881
 
698
882
class TestBzrDirCreateRepository(TestRemote):
699
883
 
720
904
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
721
905
                'False'),
722
906
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
723
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
907
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
724
908
            _client=client)
725
909
        repo = a_bzrdir.create_repository()
726
910
        # We should have got a remote repository
755
939
        client.add_success_response('stat', '0', '65535')
756
940
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
757
941
            _client=client)
758
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
942
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
759
943
            _client=client)
760
944
        repo = bzrdir.open_repository()
761
945
        self.assertEqual(
788
972
        client.add_success_response('stat', '0', '65535')
789
973
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
790
974
            _client=client)
791
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
975
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
792
976
            _client=client)
793
977
        repo = bzrdir.open_repository()
794
978
        self.assertEqual(
809
993
        transport = transport.clone('quack')
810
994
        client = FakeClient(transport.base)
811
995
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
812
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
996
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
813
997
            _client=client)
814
998
        repo = bzrdir.open_repository()
815
999
        self.assertEqual(
822
1006
 
823
1007
    def test_success(self):
824
1008
        """Simple test for typical successful call."""
825
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1009
        fmt = RemoteBzrDirFormat()
826
1010
        default_format_name = BzrDirFormat.get_default_format().network_name()
827
1011
        transport = self.get_transport()
828
1012
        client = FakeClient(transport.base)
844
1028
        """Error responses are translated, e.g. 'PermissionDenied' raises the
845
1029
        corresponding error from the client.
846
1030
        """
847
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1031
        fmt = RemoteBzrDirFormat()
848
1032
        default_format_name = BzrDirFormat.get_default_format().network_name()
849
1033
        transport = self.get_transport()
850
1034
        client = FakeClient(transport.base)
868
1052
        """Integration test for error translation."""
869
1053
        transport = self.make_smart_server('foo')
870
1054
        transport = transport.clone('no-such-path')
871
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1055
        fmt = RemoteBzrDirFormat()
872
1056
        err = self.assertRaises(errors.NoSuchFile,
873
1057
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
874
1058
 
905
1089
 
906
1090
    def make_remote_bzrdir(self, transport, client):
907
1091
        """Make a RemotebzrDir using 'client' as the _client."""
908
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1092
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
909
1093
            _client=client)
910
1094
 
911
1095
 
937
1121
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
938
1122
 
939
1123
 
 
1124
class TestBranchBreakLock(RemoteBranchTestCase):
 
1125
 
 
1126
    def test_break_lock(self):
 
1127
        transport_path = 'quack'
 
1128
        transport = MemoryTransport()
 
1129
        client = FakeClient(transport.base)
 
1130
        client.add_expected_call(
 
1131
            'Branch.get_stacked_on_url', ('quack/',),
 
1132
            'error', ('NotStacked',))
 
1133
        client.add_expected_call(
 
1134
            'Branch.break_lock', ('quack/',),
 
1135
            'success', ('ok',))
 
1136
        transport.mkdir('quack')
 
1137
        transport = transport.clone('quack')
 
1138
        branch = self.make_remote_branch(transport, client)
 
1139
        branch.break_lock()
 
1140
        self.assertFinished(client)
 
1141
 
 
1142
 
 
1143
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1144
 
 
1145
    def test_get_physical_lock_status_yes(self):
 
1146
        transport = MemoryTransport()
 
1147
        client = FakeClient(transport.base)
 
1148
        client.add_expected_call(
 
1149
            'Branch.get_stacked_on_url', ('quack/',),
 
1150
            'error', ('NotStacked',))
 
1151
        client.add_expected_call(
 
1152
            'Branch.get_physical_lock_status', ('quack/',),
 
1153
            'success', ('yes',))
 
1154
        transport.mkdir('quack')
 
1155
        transport = transport.clone('quack')
 
1156
        branch = self.make_remote_branch(transport, client)
 
1157
        result = branch.get_physical_lock_status()
 
1158
        self.assertFinished(client)
 
1159
        self.assertEqual(True, result)
 
1160
 
 
1161
    def test_get_physical_lock_status_no(self):
 
1162
        transport = MemoryTransport()
 
1163
        client = FakeClient(transport.base)
 
1164
        client.add_expected_call(
 
1165
            'Branch.get_stacked_on_url', ('quack/',),
 
1166
            'error', ('NotStacked',))
 
1167
        client.add_expected_call(
 
1168
            'Branch.get_physical_lock_status', ('quack/',),
 
1169
            'success', ('no',))
 
1170
        transport.mkdir('quack')
 
1171
        transport = transport.clone('quack')
 
1172
        branch = self.make_remote_branch(transport, client)
 
1173
        result = branch.get_physical_lock_status()
 
1174
        self.assertFinished(client)
 
1175
        self.assertEqual(False, result)
 
1176
 
 
1177
 
940
1178
class TestBranchGetParent(RemoteBranchTestCase):
941
1179
 
942
1180
    def test_no_parent(self):
1113
1351
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1114
1352
 
1115
1353
 
 
1354
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1355
 
 
1356
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1357
        transport = MemoryTransport()
 
1358
        client = FakeClient(transport.base)
 
1359
        client.add_expected_call(
 
1360
            'Branch.get_stacked_on_url', ('quack/',),
 
1361
            'error', ('NotStacked',))
 
1362
        client.add_expected_call(
 
1363
            'Branch.last_revision_info', ('quack/',),
 
1364
            'success', ('ok', '1', 'rev-tip'))
 
1365
        client.add_expected_call(
 
1366
            'Branch.get_config_file', ('quack/',),
 
1367
            'success', ('ok',), '')
 
1368
        transport.mkdir('quack')
 
1369
        transport = transport.clone('quack')
 
1370
        branch = self.make_remote_branch(transport, client)
 
1371
        result = branch.heads_to_fetch()
 
1372
        self.assertFinished(client)
 
1373
        self.assertEqual((set(['rev-tip']), set()), result)
 
1374
 
 
1375
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1376
        transport = MemoryTransport()
 
1377
        client = FakeClient(transport.base)
 
1378
        client.add_expected_call(
 
1379
            'Branch.get_stacked_on_url', ('quack/',),
 
1380
            'error', ('NotStacked',))
 
1381
        client.add_expected_call(
 
1382
            'Branch.last_revision_info', ('quack/',),
 
1383
            'success', ('ok', '1', 'rev-tip'))
 
1384
        client.add_expected_call(
 
1385
            'Branch.get_config_file', ('quack/',),
 
1386
            'success', ('ok',), 'branch.fetch_tags = True')
 
1387
        # XXX: this will break if the default format's serialization of tags
 
1388
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1389
        client.add_expected_call(
 
1390
            'Branch.get_tags_bytes', ('quack/',),
 
1391
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1392
        transport.mkdir('quack')
 
1393
        transport = transport.clone('quack')
 
1394
        branch = self.make_remote_branch(transport, client)
 
1395
        result = branch.heads_to_fetch()
 
1396
        self.assertFinished(client)
 
1397
        self.assertEqual(
 
1398
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1399
 
 
1400
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1401
        transport = MemoryTransport()
 
1402
        client = FakeClient(transport.base)
 
1403
        client.add_expected_call(
 
1404
            'Branch.get_stacked_on_url', ('quack/',),
 
1405
            'error', ('NotStacked',))
 
1406
        client.add_expected_call(
 
1407
            'Branch.heads_to_fetch', ('quack/',),
 
1408
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1409
        transport.mkdir('quack')
 
1410
        transport = transport.clone('quack')
 
1411
        branch = self.make_remote_branch(transport, client)
 
1412
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1413
        result = branch.heads_to_fetch()
 
1414
        self.assertFinished(client)
 
1415
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1416
 
 
1417
    def make_branch_with_tags(self):
 
1418
        self.setup_smart_server_with_call_log()
 
1419
        # Make a branch with a single revision.
 
1420
        builder = self.make_branch_builder('foo')
 
1421
        builder.start_series()
 
1422
        builder.build_snapshot('tip', None, [
 
1423
            ('add', ('', 'root-id', 'directory', ''))])
 
1424
        builder.finish_series()
 
1425
        branch = builder.get_branch()
 
1426
        # Add two tags to that branch
 
1427
        branch.tags.set_tag('tag-1', 'rev-1')
 
1428
        branch.tags.set_tag('tag-2', 'rev-2')
 
1429
        return branch
 
1430
 
 
1431
    def test_backwards_compatible(self):
 
1432
        branch = self.make_branch_with_tags()
 
1433
        c = branch.get_config()
 
1434
        c.set_user_option('branch.fetch_tags', 'True')
 
1435
        self.addCleanup(branch.lock_read().unlock)
 
1436
        # Disable the heads_to_fetch verb
 
1437
        verb = 'Branch.heads_to_fetch'
 
1438
        self.disable_verb(verb)
 
1439
        self.reset_smart_call_log()
 
1440
        result = branch.heads_to_fetch()
 
1441
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1442
        self.assertEqual(
 
1443
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1444
             'Branch.get_tags_bytes'],
 
1445
            [call.call.method for call in self.hpss_calls])
 
1446
 
 
1447
    def test_backwards_compatible_no_tags(self):
 
1448
        branch = self.make_branch_with_tags()
 
1449
        c = branch.get_config()
 
1450
        c.set_user_option('branch.fetch_tags', 'False')
 
1451
        self.addCleanup(branch.lock_read().unlock)
 
1452
        # Disable the heads_to_fetch verb
 
1453
        verb = 'Branch.heads_to_fetch'
 
1454
        self.disable_verb(verb)
 
1455
        self.reset_smart_call_log()
 
1456
        result = branch.heads_to_fetch()
 
1457
        self.assertEqual((set(['tip']), set()), result)
 
1458
        self.assertEqual(
 
1459
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1460
            [call.call.method for call in self.hpss_calls])
 
1461
 
 
1462
 
1116
1463
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1117
1464
 
1118
1465
    def test_empty_branch(self):
1173
1520
        client.add_expected_call(
1174
1521
            'Branch.get_stacked_on_url', ('stacked/',),
1175
1522
            'success', ('ok', vfs_url))
1176
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1523
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1177
1524
            _client=client)
1178
1525
        repo_fmt = remote.RemoteRepositoryFormat()
1179
1526
        repo_fmt._custom_format = stacked_branch.repository._format
1190
1537
        client = FakeClient(self.get_url())
1191
1538
        branch_network_name = self.get_branch_format().network_name()
1192
1539
        client.add_expected_call(
1193
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1540
            'BzrDir.open_branchV3', ('stacked/',),
1194
1541
            'success', ('branch', branch_network_name))
1195
1542
        client.add_expected_call(
1196
1543
            'BzrDir.find_repositoryV3', ('stacked/',),
1206
1553
        # this will also do vfs access, but that goes direct to the transport
1207
1554
        # and isn't seen by the FakeClient.
1208
1555
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1209
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1556
            RemoteBzrDirFormat(), _client=client)
1210
1557
        branch = bzrdir.open_branch()
1211
1558
        result = branch.get_stacked_on_url()
1212
1559
        self.assertEqual('../base', result)
1218
1565
            len(branch.repository._real_repository._fallback_repositories))
1219
1566
 
1220
1567
    def test_get_stacked_on_real_branch(self):
1221
 
        base_branch = self.make_branch('base', format='1.6')
1222
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1568
        base_branch = self.make_branch('base')
 
1569
        stacked_branch = self.make_branch('stacked')
1223
1570
        stacked_branch.set_stacked_on_url('../base')
1224
1571
        reference_format = self.get_repo_format()
1225
1572
        network_name = reference_format.network_name()
1226
1573
        client = FakeClient(self.get_url())
1227
1574
        branch_network_name = self.get_branch_format().network_name()
1228
1575
        client.add_expected_call(
1229
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1576
            'BzrDir.open_branchV3', ('stacked/',),
1230
1577
            'success', ('branch', branch_network_name))
1231
1578
        client.add_expected_call(
1232
1579
            'BzrDir.find_repositoryV3', ('stacked/',),
1233
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1580
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1234
1581
        # called twice, once from constructor and then again by us
1235
1582
        client.add_expected_call(
1236
1583
            'Branch.get_stacked_on_url', ('stacked/',),
1239
1586
            'Branch.get_stacked_on_url', ('stacked/',),
1240
1587
            'success', ('ok', '../base'))
1241
1588
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1242
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1589
            RemoteBzrDirFormat(), _client=client)
1243
1590
        branch = bzrdir.open_branch()
1244
1591
        result = branch.get_stacked_on_url()
1245
1592
        self.assertEqual('../base', result)
1253
1600
class TestBranchSetLastRevision(RemoteBranchTestCase):
1254
1601
 
1255
1602
    def test_set_empty(self):
1256
 
        # set_revision_history([]) is translated to calling
 
1603
        # _set_last_revision_info('null:') is translated to calling
1257
1604
        # Branch.set_last_revision(path, '') on the wire.
1258
1605
        transport = MemoryTransport()
1259
1606
        transport.mkdir('branch')
1277
1624
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1278
1625
            'success', ('ok',))
1279
1626
        branch = self.make_remote_branch(transport, client)
1280
 
        # This is a hack to work around the problem that RemoteBranch currently
1281
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1282
 
        branch._ensure_real = lambda: None
1283
1627
        branch.lock_write()
1284
 
        result = branch.set_revision_history([])
 
1628
        result = branch._set_last_revision(NULL_REVISION)
1285
1629
        branch.unlock()
1286
1630
        self.assertEqual(None, result)
1287
1631
        self.assertFinished(client)
1288
1632
 
1289
1633
    def test_set_nonempty(self):
1290
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1634
        # set_last_revision_info(N, rev-idN) is translated to calling
1291
1635
        # Branch.set_last_revision(path, rev-idN) on the wire.
1292
1636
        transport = MemoryTransport()
1293
1637
        transport.mkdir('branch')
1314
1658
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1315
1659
            'success', ('ok',))
1316
1660
        branch = self.make_remote_branch(transport, client)
1317
 
        # This is a hack to work around the problem that RemoteBranch currently
1318
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1319
 
        branch._ensure_real = lambda: None
1320
1661
        # Lock the branch, reset the record of remote calls.
1321
1662
        branch.lock_write()
1322
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1663
        result = branch._set_last_revision('rev-id2')
1323
1664
        branch.unlock()
1324
1665
        self.assertEqual(None, result)
1325
1666
        self.assertFinished(client)
1355
1696
        branch = self.make_remote_branch(transport, client)
1356
1697
        branch.lock_write()
1357
1698
        self.assertRaises(
1358
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1699
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1359
1700
        branch.unlock()
1360
1701
        self.assertFinished(client)
1361
1702
 
1389
1730
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1390
1731
            'success', ('ok',))
1391
1732
        branch = self.make_remote_branch(transport, client)
1392
 
        branch._ensure_real = lambda: None
1393
1733
        branch.lock_write()
1394
1734
        # The 'TipChangeRejected' error response triggered by calling
1395
 
        # set_revision_history causes a TipChangeRejected exception.
 
1735
        # set_last_revision_info causes a TipChangeRejected exception.
1396
1736
        err = self.assertRaises(
1397
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1737
            errors.TipChangeRejected,
 
1738
            branch._set_last_revision, 'rev-id')
1398
1739
        # The UTF-8 message from the response has been decoded into a unicode
1399
1740
        # object.
1400
1741
        self.assertIsInstance(err.msg, unicode)
1588
1929
    def test_get_multi_line_branch_conf(self):
1589
1930
        # Make sure that multiple-line branch.conf files are supported
1590
1931
        #
1591
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1932
        # https://bugs.launchpad.net/bzr/+bug/354075
1592
1933
        client = FakeClient()
1593
1934
        client.add_expected_call(
1594
1935
            'Branch.get_stacked_on_url', ('memory:///',),
1622
1963
        branch.unlock()
1623
1964
        self.assertFinished(client)
1624
1965
 
 
1966
    def test_set_option_with_dict(self):
 
1967
        client = FakeClient()
 
1968
        client.add_expected_call(
 
1969
            'Branch.get_stacked_on_url', ('memory:///',),
 
1970
            'error', ('NotStacked',),)
 
1971
        client.add_expected_call(
 
1972
            'Branch.lock_write', ('memory:///', '', ''),
 
1973
            'success', ('ok', 'branch token', 'repo token'))
 
1974
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1975
        client.add_expected_call(
 
1976
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1977
            'repo token', encoded_dict_value, 'foo', ''),
 
1978
            'success', ())
 
1979
        client.add_expected_call(
 
1980
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1981
            'success', ('ok',))
 
1982
        transport = MemoryTransport()
 
1983
        branch = self.make_remote_branch(transport, client)
 
1984
        branch.lock_write()
 
1985
        config = branch._get_config()
 
1986
        config.set_option(
 
1987
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1988
            'foo')
 
1989
        branch.unlock()
 
1990
        self.assertFinished(client)
 
1991
 
1625
1992
    def test_backwards_compat_set_option(self):
1626
1993
        self.setup_smart_server_with_call_log()
1627
1994
        branch = self.make_branch('.')
1634
2001
        self.assertLength(10, self.hpss_calls)
1635
2002
        self.assertEqual('value', branch._get_config().get_option('name'))
1636
2003
 
 
2004
    def test_backwards_compat_set_option_with_dict(self):
 
2005
        self.setup_smart_server_with_call_log()
 
2006
        branch = self.make_branch('.')
 
2007
        verb = 'Branch.set_config_option_dict'
 
2008
        self.disable_verb(verb)
 
2009
        branch.lock_write()
 
2010
        self.addCleanup(branch.unlock)
 
2011
        self.reset_smart_call_log()
 
2012
        config = branch._get_config()
 
2013
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2014
        config.set_option(value_dict, 'name')
 
2015
        self.assertLength(10, self.hpss_calls)
 
2016
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2017
 
 
2018
 
 
2019
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2020
 
 
2021
    def test_get_branch_conf(self):
 
2022
        # in an empty branch we decode the response properly
 
2023
        client = FakeClient()
 
2024
        client.add_expected_call(
 
2025
            'Branch.get_stacked_on_url', ('memory:///',),
 
2026
            'error', ('NotStacked',),)
 
2027
        client.add_success_response_with_body('# config file body', 'ok')
 
2028
        transport = MemoryTransport()
 
2029
        branch = self.make_remote_branch(transport, client)
 
2030
        config = branch.get_config_stack()
 
2031
        config.get("email")
 
2032
        config.get("log_format")
 
2033
        self.assertEqual(
 
2034
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2035
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2036
            client._calls)
 
2037
 
 
2038
    def test_set_branch_conf(self):
 
2039
        client = FakeClient()
 
2040
        client.add_expected_call(
 
2041
            'Branch.get_stacked_on_url', ('memory:///',),
 
2042
            'error', ('NotStacked',),)
 
2043
        client.add_expected_call(
 
2044
            'Branch.lock_write', ('memory:///', '', ''),
 
2045
            'success', ('ok', 'branch token', 'repo token'))
 
2046
        client.add_expected_call(
 
2047
            'Branch.get_config_file', ('memory:///', ),
 
2048
            'success', ('ok', ), "# line 1\n")
 
2049
        client.add_expected_call(
 
2050
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2051
            'repo token'),
 
2052
            'success', ('ok',))
 
2053
        client.add_expected_call(
 
2054
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2055
            'success', ('ok',))
 
2056
        transport = MemoryTransport()
 
2057
        branch = self.make_remote_branch(transport, client)
 
2058
        branch.lock_write()
 
2059
        config = branch.get_config_stack()
 
2060
        config.set('email', 'The Dude <lebowski@example.com>')
 
2061
        branch.unlock()
 
2062
        self.assertFinished(client)
 
2063
        self.assertEqual(
 
2064
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2065
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2066
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2067
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2068
                 ('memory:///', 'branch token', 'repo token'),
 
2069
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2070
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2071
            client._calls)
 
2072
 
1637
2073
 
1638
2074
class TestBranchLockWrite(RemoteBranchTestCase):
1639
2075
 
1653
2089
        self.assertFinished(client)
1654
2090
 
1655
2091
 
 
2092
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2093
 
 
2094
    def test_simple(self):
 
2095
        transport = MemoryTransport()
 
2096
        client = FakeClient(transport.base)
 
2097
        client.add_expected_call(
 
2098
            'Branch.get_stacked_on_url', ('quack/',),
 
2099
            'error', ('NotStacked',),)
 
2100
        client.add_expected_call(
 
2101
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2102
            'success', ('ok', '0',),)
 
2103
        client.add_expected_call(
 
2104
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2105
            'error', ('NoSuchRevision', 'unknown',),)
 
2106
        transport.mkdir('quack')
 
2107
        transport = transport.clone('quack')
 
2108
        branch = self.make_remote_branch(transport, client)
 
2109
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2110
        self.assertRaises(errors.NoSuchRevision,
 
2111
            branch.revision_id_to_revno, 'unknown')
 
2112
        self.assertFinished(client)
 
2113
 
 
2114
    def test_dotted(self):
 
2115
        transport = MemoryTransport()
 
2116
        client = FakeClient(transport.base)
 
2117
        client.add_expected_call(
 
2118
            'Branch.get_stacked_on_url', ('quack/',),
 
2119
            'error', ('NotStacked',),)
 
2120
        client.add_expected_call(
 
2121
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2122
            'success', ('ok', '0',),)
 
2123
        client.add_expected_call(
 
2124
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2125
            'error', ('NoSuchRevision', 'unknown',),)
 
2126
        transport.mkdir('quack')
 
2127
        transport = transport.clone('quack')
 
2128
        branch = self.make_remote_branch(transport, client)
 
2129
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2130
        self.assertRaises(errors.NoSuchRevision,
 
2131
            branch.revision_id_to_dotted_revno, 'unknown')
 
2132
        self.assertFinished(client)
 
2133
 
 
2134
    def test_dotted_no_smart_verb(self):
 
2135
        self.setup_smart_server_with_call_log()
 
2136
        branch = self.make_branch('.')
 
2137
        self.disable_verb('Branch.revision_id_to_revno')
 
2138
        self.reset_smart_call_log()
 
2139
        self.assertEquals((0, ),
 
2140
            branch.revision_id_to_dotted_revno('null:'))
 
2141
        self.assertLength(7, self.hpss_calls)
 
2142
 
 
2143
 
1656
2144
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1657
2145
 
1658
2146
    def test__get_config(self):
1775
2263
        client = FakeClient(transport.base)
1776
2264
        transport = transport.clone(transport_path)
1777
2265
        # we do not want bzrdir to make any remote calls
1778
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2266
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1779
2267
            _client=False)
1780
2268
        repo = RemoteRepository(bzrdir, None, _client=client)
1781
2269
        return repo, client
1789
2277
 
1790
2278
    def test_get_format_description(self):
1791
2279
        remote_format = RemoteBranchFormat()
1792
 
        real_format = branch.BranchFormat.get_default_format()
 
2280
        real_format = branch.format_registry.get_default()
1793
2281
        remote_format._network_name = real_format.network_name()
1794
2282
        self.assertEqual(remoted_description(real_format),
1795
2283
            remote_format.get_format_description())
1798
2286
class TestRepositoryFormat(TestRemoteRepository):
1799
2287
 
1800
2288
    def test_fast_delta(self):
1801
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2289
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1802
2290
        true_format = RemoteRepositoryFormat()
1803
2291
        true_format._network_name = true_name
1804
2292
        self.assertEqual(True, true_format.fast_deltas)
1805
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2293
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1806
2294
        false_format = RemoteRepositoryFormat()
1807
2295
        false_format._network_name = false_name
1808
2296
        self.assertEqual(False, false_format.fast_deltas)
1809
2297
 
1810
2298
    def test_get_format_description(self):
1811
2299
        remote_repo_format = RemoteRepositoryFormat()
1812
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2300
        real_format = repository.format_registry.get_default()
1813
2301
        remote_repo_format._network_name = real_format.network_name()
1814
2302
        self.assertEqual(remoted_description(real_format),
1815
2303
            remote_repo_format.get_format_description())
1816
2304
 
1817
2305
 
 
2306
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2307
 
 
2308
    def test_empty(self):
 
2309
        transport_path = 'quack'
 
2310
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2311
        client.add_success_response_with_body('', 'ok')
 
2312
        self.assertEquals([], repo.all_revision_ids())
 
2313
        self.assertEqual(
 
2314
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2315
             ('quack/',))],
 
2316
            client._calls)
 
2317
 
 
2318
    def test_with_some_content(self):
 
2319
        transport_path = 'quack'
 
2320
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2321
        client.add_success_response_with_body(
 
2322
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2323
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2324
            repo.all_revision_ids())
 
2325
        self.assertEqual(
 
2326
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2327
             ('quack/',))],
 
2328
            client._calls)
 
2329
 
 
2330
 
1818
2331
class TestRepositoryGatherStats(TestRemoteRepository):
1819
2332
 
1820
2333
    def test_revid_none(self):
1873
2386
                         result)
1874
2387
 
1875
2388
 
 
2389
class TestRepositoryBreakLock(TestRemoteRepository):
 
2390
 
 
2391
    def test_break_lock(self):
 
2392
        transport_path = 'quack'
 
2393
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2394
        client.add_success_response('ok')
 
2395
        repo.break_lock()
 
2396
        self.assertEqual(
 
2397
            [('call', 'Repository.break_lock', ('quack/',))],
 
2398
            client._calls)
 
2399
 
 
2400
 
 
2401
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2402
 
 
2403
    def test_get_serializer_format(self):
 
2404
        transport_path = 'hill'
 
2405
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2406
        client.add_success_response('ok', '7')
 
2407
        self.assertEquals('7', repo.get_serializer_format())
 
2408
        self.assertEqual(
 
2409
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2410
              ('hill/', ))],
 
2411
            client._calls)
 
2412
 
 
2413
 
 
2414
class TestRepositoryReconcile(TestRemoteRepository):
 
2415
 
 
2416
    def test_reconcile(self):
 
2417
        transport_path = 'hill'
 
2418
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2419
        body = ("garbage_inventories: 2\n"
 
2420
                "inconsistent_parents: 3\n")
 
2421
        client.add_expected_call(
 
2422
            'Repository.lock_write', ('hill/', ''),
 
2423
            'success', ('ok', 'a token'))
 
2424
        client.add_success_response_with_body(body, 'ok')
 
2425
        reconciler = repo.reconcile()
 
2426
        self.assertEqual(
 
2427
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2428
             ('call_expecting_body', 'Repository.reconcile',
 
2429
                ('hill/', 'a token'))],
 
2430
            client._calls)
 
2431
        self.assertEquals(2, reconciler.garbage_inventories)
 
2432
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2433
 
 
2434
 
 
2435
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2436
 
 
2437
    def test_text(self):
 
2438
        # ('ok',), body with signature text
 
2439
        transport_path = 'quack'
 
2440
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2441
        client.add_success_response_with_body(
 
2442
            'THETEXT', 'ok')
 
2443
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2444
        self.assertEqual(
 
2445
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2446
             ('quack/', 'revid'))],
 
2447
            client._calls)
 
2448
 
 
2449
    def test_no_signature(self):
 
2450
        transport_path = 'quick'
 
2451
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2452
        client.add_error_response('nosuchrevision', 'unknown')
 
2453
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2454
                "unknown")
 
2455
        self.assertEqual(
 
2456
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2457
              ('quick/', 'unknown'))],
 
2458
            client._calls)
 
2459
 
 
2460
 
1876
2461
class TestRepositoryGetGraph(TestRemoteRepository):
1877
2462
 
1878
2463
    def test_get_graph(self):
1883
2468
        self.assertNotEqual(graph._parents_provider, repo)
1884
2469
 
1885
2470
 
 
2471
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2472
 
 
2473
    def test_add_signature_text(self):
 
2474
        transport_path = 'quack'
 
2475
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2476
        client.add_expected_call(
 
2477
            'Repository.lock_write', ('quack/', ''),
 
2478
            'success', ('ok', 'a token'))
 
2479
        client.add_expected_call(
 
2480
            'Repository.start_write_group', ('quack/', 'a token'),
 
2481
            'success', ('ok', ('token1', )))
 
2482
        client.add_expected_call(
 
2483
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2484
                'token1'),
 
2485
            'success', ('ok', ), None)
 
2486
        repo.lock_write()
 
2487
        repo.start_write_group()
 
2488
        self.assertIs(None,
 
2489
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2490
        self.assertEqual(
 
2491
            ('call_with_body_bytes_expecting_body',
 
2492
              'Repository.add_signature_text',
 
2493
                ('quack/', 'a token', 'rev1', 'token1'),
 
2494
              'every bloody emperor'),
 
2495
            client._calls[-1])
 
2496
 
 
2497
 
1886
2498
class TestRepositoryGetParentMap(TestRemoteRepository):
1887
2499
 
1888
2500
    def test_get_parent_map_caching(self):
1938
2550
        parents = repo.get_parent_map([rev_id])
1939
2551
        self.assertEqual(
1940
2552
            [('call_with_body_bytes_expecting_body',
1941
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1942
 
              rev_id), '\n\n0'),
 
2553
              'Repository.get_parent_map',
 
2554
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1943
2555
             ('disconnect medium',),
1944
2556
             ('call_expecting_body', 'Repository.get_revision_graph',
1945
2557
              ('quack/', ''))],
2004
2616
        self.assertLength(1, self.hpss_calls)
2005
2617
 
2006
2618
    def disableExtraResults(self):
2007
 
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
2008
 
        SmartServerRepositoryGetParentMap.no_extra_results = True
2009
 
        def reset_values():
2010
 
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
2011
 
        self.addCleanup(reset_values)
 
2619
        self.overrideAttr(SmartServerRepositoryGetParentMap,
 
2620
                          'no_extra_results', True)
2012
2621
 
2013
2622
    def test_null_cached_missing_and_stop_key(self):
2014
2623
        self.setup_smart_server_with_call_log()
2068
2677
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2069
2678
        self.assertLength(0, self.hpss_calls)
2070
2679
 
 
2680
    def test_exposes_get_cached_parent_map(self):
 
2681
        """RemoteRepository exposes get_cached_parent_map from
 
2682
        _unstacked_provider
 
2683
        """
 
2684
        r1 = u'\u0e33'.encode('utf8')
 
2685
        r2 = u'\u0dab'.encode('utf8')
 
2686
        lines = [' '.join([r2, r1]), r1]
 
2687
        encoded_body = bz2.compress('\n'.join(lines))
 
2688
 
 
2689
        transport_path = 'quack'
 
2690
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2691
        client.add_success_response_with_body(encoded_body, 'ok')
 
2692
        repo.lock_read()
 
2693
        # get_cached_parent_map should *not* trigger an RPC
 
2694
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2695
        self.assertEqual([], client._calls)
 
2696
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2697
        self.assertEqual({r1: (NULL_REVISION,)},
 
2698
            repo.get_cached_parent_map([r1]))
 
2699
        self.assertEqual(
 
2700
            [('call_with_body_bytes_expecting_body',
 
2701
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2702
              '\n\n0')],
 
2703
            client._calls)
 
2704
        repo.unlock()
 
2705
 
2071
2706
 
2072
2707
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2073
2708
 
2074
2709
    def test_allows_new_revisions(self):
2075
2710
        """get_parent_map's results can be updated by commit."""
2076
 
        smart_server = server.SmartTCPServer_for_testing()
 
2711
        smart_server = test_server.SmartTCPServer_for_testing()
2077
2712
        self.start_server(smart_server)
2078
2713
        self.make_branch('branch')
2079
2714
        branch = Branch.open(smart_server.get_url() + '/branch')
2088
2723
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2089
2724
 
2090
2725
 
 
2726
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2727
 
 
2728
    def test_hpss_missing_revision(self):
 
2729
        transport_path = 'quack'
 
2730
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2731
        client.add_success_response_with_body(
 
2732
            '', 'ok', '10')
 
2733
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2734
            ['somerev1', 'anotherrev2'])
 
2735
        self.assertEqual(
 
2736
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2737
             ('quack/', ), "somerev1\nanotherrev2")],
 
2738
            client._calls)
 
2739
 
 
2740
    def test_hpss_get_single_revision(self):
 
2741
        transport_path = 'quack'
 
2742
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2743
        somerev1 = Revision("somerev1")
 
2744
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2745
        somerev1.timestamp = 1321828927
 
2746
        somerev1.timezone = -60
 
2747
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2748
        somerev1.message = "Message"
 
2749
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2750
            somerev1))
 
2751
        # Split up body into two bits to make sure the zlib compression object
 
2752
        # gets data fed twice.
 
2753
        client.add_success_response_with_body(
 
2754
                [body[:10], body[10:]], 'ok', '10')
 
2755
        revs = repo.get_revisions(['somerev1'])
 
2756
        self.assertEquals(revs, [somerev1])
 
2757
        self.assertEqual(
 
2758
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2759
             ('quack/', ), "somerev1")],
 
2760
            client._calls)
 
2761
 
 
2762
 
2091
2763
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2092
2764
 
2093
2765
    def test_null_revision(self):
2189
2861
        """
2190
2862
        # Make a repo with a fallback repo, both using a FakeClient.
2191
2863
        format = remote.response_tuple_to_repo_format(
2192
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2864
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2193
2865
        repo, client = self.setup_fake_client_and_repository('quack')
2194
2866
        repo._format = format
2195
2867
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2196
2868
            'fallback')
2197
2869
        fallback_repo._client = client
 
2870
        fallback_repo._format = format
2198
2871
        repo.add_fallback_repository(fallback_repo)
2199
2872
        # First the client should ask the primary repo
2200
2873
        client.add_expected_call(
2229
2902
        self.setup_smart_server_with_call_log()
2230
2903
        tree = self.make_branch_and_memory_tree('.')
2231
2904
        tree.lock_write()
 
2905
        tree.add('')
2232
2906
        rev1 = tree.commit('First')
2233
2907
        rev2 = tree.commit('Second')
2234
2908
        tree.unlock()
2242
2916
                              call.call.method == verb])
2243
2917
 
2244
2918
 
 
2919
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2920
 
 
2921
    def test_has_signature_for_revision_id(self):
 
2922
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2923
        transport_path = 'quack'
 
2924
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2925
        client.add_success_response('yes')
 
2926
        result = repo.has_signature_for_revision_id('A')
 
2927
        self.assertEqual(
 
2928
            [('call', 'Repository.has_signature_for_revision_id',
 
2929
              ('quack/', 'A'))],
 
2930
            client._calls)
 
2931
        self.assertEqual(True, result)
 
2932
 
 
2933
    def test_is_not_shared(self):
 
2934
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2935
        transport_path = 'qwack'
 
2936
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2937
        client.add_success_response('no')
 
2938
        result = repo.has_signature_for_revision_id('A')
 
2939
        self.assertEqual(
 
2940
            [('call', 'Repository.has_signature_for_revision_id',
 
2941
              ('qwack/', 'A'))],
 
2942
            client._calls)
 
2943
        self.assertEqual(False, result)
 
2944
 
 
2945
 
 
2946
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2947
 
 
2948
    def test_get_physical_lock_status_yes(self):
 
2949
        transport_path = 'qwack'
 
2950
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2951
        client.add_success_response('yes')
 
2952
        result = repo.get_physical_lock_status()
 
2953
        self.assertEqual(
 
2954
            [('call', 'Repository.get_physical_lock_status',
 
2955
              ('qwack/', ))],
 
2956
            client._calls)
 
2957
        self.assertEqual(True, result)
 
2958
 
 
2959
    def test_get_physical_lock_status_no(self):
 
2960
        transport_path = 'qwack'
 
2961
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2962
        client.add_success_response('no')
 
2963
        result = repo.get_physical_lock_status()
 
2964
        self.assertEqual(
 
2965
            [('call', 'Repository.get_physical_lock_status',
 
2966
              ('qwack/', ))],
 
2967
            client._calls)
 
2968
        self.assertEqual(False, result)
 
2969
 
 
2970
 
2245
2971
class TestRepositoryIsShared(TestRemoteRepository):
2246
2972
 
2247
2973
    def test_is_shared(self):
2267
2993
        self.assertEqual(False, result)
2268
2994
 
2269
2995
 
 
2996
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
2997
 
 
2998
    def test_make_working_trees(self):
 
2999
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3000
        transport_path = 'quack'
 
3001
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3002
        client.add_success_response('yes')
 
3003
        result = repo.make_working_trees()
 
3004
        self.assertEqual(
 
3005
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3006
            client._calls)
 
3007
        self.assertEqual(True, result)
 
3008
 
 
3009
    def test_no_working_trees(self):
 
3010
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3011
        transport_path = 'qwack'
 
3012
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3013
        client.add_success_response('no')
 
3014
        result = repo.make_working_trees()
 
3015
        self.assertEqual(
 
3016
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3017
            client._calls)
 
3018
        self.assertEqual(False, result)
 
3019
 
 
3020
 
2270
3021
class TestRepositoryLockWrite(TestRemoteRepository):
2271
3022
 
2272
3023
    def test_lock_write(self):
2273
3024
        transport_path = 'quack'
2274
3025
        repo, client = self.setup_fake_client_and_repository(transport_path)
2275
3026
        client.add_success_response('ok', 'a token')
2276
 
        result = repo.lock_write()
 
3027
        token = repo.lock_write().repository_token
2277
3028
        self.assertEqual(
2278
3029
            [('call', 'Repository.lock_write', ('quack/', ''))],
2279
3030
            client._calls)
2280
 
        self.assertEqual('a token', result)
 
3031
        self.assertEqual('a token', token)
2281
3032
 
2282
3033
    def test_lock_write_already_locked(self):
2283
3034
        transport_path = 'quack'
2298
3049
            client._calls)
2299
3050
 
2300
3051
 
 
3052
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3053
 
 
3054
    def test_start_write_group(self):
 
3055
        transport_path = 'quack'
 
3056
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3057
        client.add_expected_call(
 
3058
            'Repository.lock_write', ('quack/', ''),
 
3059
            'success', ('ok', 'a token'))
 
3060
        client.add_expected_call(
 
3061
            'Repository.start_write_group', ('quack/', 'a token'),
 
3062
            'success', ('ok', ('token1', )))
 
3063
        repo.lock_write()
 
3064
        repo.start_write_group()
 
3065
 
 
3066
    def test_start_write_group_unsuspendable(self):
 
3067
        # Some repositories do not support suspending write
 
3068
        # groups. For those, fall back to the "real" repository.
 
3069
        transport_path = 'quack'
 
3070
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3071
        def stub_ensure_real():
 
3072
            client._calls.append(('_ensure_real',))
 
3073
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3074
        repo._ensure_real = stub_ensure_real
 
3075
        client.add_expected_call(
 
3076
            'Repository.lock_write', ('quack/', ''),
 
3077
            'success', ('ok', 'a token'))
 
3078
        client.add_expected_call(
 
3079
            'Repository.start_write_group', ('quack/', 'a token'),
 
3080
            'error', ('UnsuspendableWriteGroup',))
 
3081
        repo.lock_write()
 
3082
        repo.start_write_group()
 
3083
        self.assertEquals(client._calls[-2:], [ 
 
3084
            ('_ensure_real',),
 
3085
            ('start_write_group',)])
 
3086
 
 
3087
    def test_commit_write_group(self):
 
3088
        transport_path = 'quack'
 
3089
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3090
        client.add_expected_call(
 
3091
            'Repository.lock_write', ('quack/', ''),
 
3092
            'success', ('ok', 'a token'))
 
3093
        client.add_expected_call(
 
3094
            'Repository.start_write_group', ('quack/', 'a token'),
 
3095
            'success', ('ok', ['token1']))
 
3096
        client.add_expected_call(
 
3097
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3098
            'success', ('ok',))
 
3099
        repo.lock_write()
 
3100
        repo.start_write_group()
 
3101
        repo.commit_write_group()
 
3102
 
 
3103
    def test_abort_write_group(self):
 
3104
        transport_path = 'quack'
 
3105
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3106
        client.add_expected_call(
 
3107
            'Repository.lock_write', ('quack/', ''),
 
3108
            'success', ('ok', 'a token'))
 
3109
        client.add_expected_call(
 
3110
            'Repository.start_write_group', ('quack/', 'a token'),
 
3111
            'success', ('ok', ['token1']))
 
3112
        client.add_expected_call(
 
3113
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3114
            'success', ('ok',))
 
3115
        repo.lock_write()
 
3116
        repo.start_write_group()
 
3117
        repo.abort_write_group(False)
 
3118
 
 
3119
    def test_suspend_write_group(self):
 
3120
        transport_path = 'quack'
 
3121
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3122
        self.assertEquals([], repo.suspend_write_group())
 
3123
 
 
3124
    def test_resume_write_group(self):
 
3125
        transport_path = 'quack'
 
3126
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3127
        client.add_expected_call(
 
3128
            'Repository.lock_write', ('quack/', ''),
 
3129
            'success', ('ok', 'a token'))
 
3130
        client.add_expected_call(
 
3131
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3132
            'success', ('ok',))
 
3133
        repo.lock_write()
 
3134
        repo.resume_write_group(['token1'])
 
3135
 
 
3136
 
2301
3137
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2302
3138
 
2303
3139
    def test_backwards_compat(self):
2362
3198
        self.assertEqual([], client._calls)
2363
3199
 
2364
3200
 
 
3201
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3202
    """Test Repository.iter_file_bytes."""
 
3203
 
 
3204
    def test_single(self):
 
3205
        transport_path = 'quack'
 
3206
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3207
        client.add_expected_call(
 
3208
            'Repository.iter_files_bytes', ('quack/', ),
 
3209
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3210
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3211
                "somerev", "myid")]):
 
3212
            self.assertEquals("myid", identifier)
 
3213
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3214
 
 
3215
    def test_missing(self):
 
3216
        transport_path = 'quack'
 
3217
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3218
        client.add_expected_call(
 
3219
            'Repository.iter_files_bytes',
 
3220
                ('quack/', ),
 
3221
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3222
            iter(["absent\0somefile\0somerev\n"]))
 
3223
        self.assertRaises(errors.RevisionNotPresent, list,
 
3224
                repo.iter_files_bytes(
 
3225
                [("somefile", "somerev", "myid")]))
 
3226
 
 
3227
 
2365
3228
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2366
3229
    """Base class for Repository.insert_stream and .insert_stream_1.19
2367
3230
    tests.
2374
3237
        the client is finished.
2375
3238
        """
2376
3239
        sink = repo._get_sink()
2377
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3240
        fmt = repository.format_registry.get_default()
2378
3241
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2379
3242
        self.assertEqual([], resume_tokens)
2380
3243
        self.assertEqual(set(), missing_keys)
2480
3343
                return True
2481
3344
        repo._real_repository = FakeRealRepository()
2482
3345
        sink = repo._get_sink()
2483
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3346
        fmt = repository.format_registry.get_default()
2484
3347
        stream = self.make_stream_with_inv_deltas(fmt)
2485
3348
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2486
3349
        # Every record from the first inventory delta should have been sent to
2621
3484
    """RemoteRepository.copy_content_into optimizations"""
2622
3485
 
2623
3486
    def test_copy_content_remote_to_local(self):
2624
 
        self.transport_server = server.SmartTCPServer_for_testing
 
3487
        self.transport_server = test_server.SmartTCPServer_for_testing
2625
3488
        src_repo = self.make_repository('repo1')
2626
3489
        src_repo = repository.Repository.open(self.get_url('repo1'))
2627
3490
        # At the moment the tarball-based copy_content_into can't write back
2642
3505
        self.calls = calls
2643
3506
        self._pack_collection = _StubPackCollection(calls)
2644
3507
 
 
3508
    def start_write_group(self):
 
3509
        self.calls.append(('start_write_group',))
 
3510
 
2645
3511
    def is_in_write_group(self):
2646
3512
        return False
2647
3513
 
2706
3572
             ('pack collection autopack',)],
2707
3573
            client._calls)
2708
3574
 
 
3575
    def test_oom_error_reporting(self):
 
3576
        """An out-of-memory condition on the server is reported clearly"""
 
3577
        transport_path = 'quack'
 
3578
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3579
        client.add_expected_call(
 
3580
            'PackRepository.autopack', ('quack/',),
 
3581
            'error', ('MemoryError',))
 
3582
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3583
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3584
 
2709
3585
 
2710
3586
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2711
3587
    """Base class for unit tests for bzrlib.remote._translate_error."""
2775
3651
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2776
3652
        self.assertEqual(expected_error, translated_error)
2777
3653
 
 
3654
    def test_nobranch_one_arg(self):
 
3655
        bzrdir = self.make_bzrdir('')
 
3656
        translated_error = self.translateTuple(
 
3657
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
 
3658
        expected_error = errors.NotBranchError(
 
3659
            path=bzrdir.root_transport.base,
 
3660
            detail='extra detail')
 
3661
        self.assertEqual(expected_error, translated_error)
 
3662
 
 
3663
    def test_norepository(self):
 
3664
        bzrdir = self.make_bzrdir('')
 
3665
        translated_error = self.translateTuple(('norepository',),
 
3666
            bzrdir=bzrdir)
 
3667
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3668
        self.assertEqual(expected_error, translated_error)
 
3669
 
2778
3670
    def test_LockContention(self):
2779
3671
        translated_error = self.translateTuple(('LockContention',))
2780
3672
        expected_error = errors.LockContention('(remote lock)')
2808
3700
        expected_error = errors.DivergedBranches(branch, other_branch)
2809
3701
        self.assertEqual(expected_error, translated_error)
2810
3702
 
 
3703
    def test_NotStacked(self):
 
3704
        branch = self.make_branch('')
 
3705
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3706
        expected_error = errors.NotStacked(branch)
 
3707
        self.assertEqual(expected_error, translated_error)
 
3708
 
2811
3709
    def test_ReadError_no_args(self):
2812
3710
        path = 'a path'
2813
3711
        translated_error = self.translateTuple(('ReadError',), path=path)
2829
3727
 
2830
3728
    def test_PermissionDenied_no_args(self):
2831
3729
        path = 'a path'
2832
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3730
        translated_error = self.translateTuple(('PermissionDenied',),
 
3731
            path=path)
2833
3732
        expected_error = errors.PermissionDenied(path)
2834
3733
        self.assertEqual(expected_error, translated_error)
2835
3734
 
2858
3757
        expected_error = errors.PermissionDenied(path, extra)
2859
3758
        self.assertEqual(expected_error, translated_error)
2860
3759
 
 
3760
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3761
 
 
3762
    def test_NoSuchFile_context_path(self):
 
3763
        local_path = "local path"
 
3764
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3765
            path=local_path)
 
3766
        expected_error = errors.ReadError(local_path)
 
3767
        self.assertEqual(expected_error, translated_error)
 
3768
 
 
3769
    def test_NoSuchFile_without_context(self):
 
3770
        remote_path = "remote path"
 
3771
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3772
        expected_error = errors.ReadError(remote_path)
 
3773
        self.assertEqual(expected_error, translated_error)
 
3774
 
 
3775
    def test_ReadOnlyError(self):
 
3776
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3777
        expected_error = errors.TransportNotPossible("readonly transport")
 
3778
        self.assertEqual(expected_error, translated_error)
 
3779
 
 
3780
    def test_MemoryError(self):
 
3781
        translated_error = self.translateTuple(('MemoryError',))
 
3782
        self.assertStartsWith(str(translated_error),
 
3783
            "remote server out of memory")
 
3784
 
 
3785
    def test_generic_IndexError_no_classname(self):
 
3786
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3787
        translated_error = self.translateErrorFromSmartServer(err)
 
3788
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3789
        self.assertEqual(expected_error, translated_error)
 
3790
 
 
3791
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3792
 
 
3793
    def test_generic_KeyError(self):
 
3794
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3795
        translated_error = self.translateErrorFromSmartServer(err)
 
3796
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3797
        self.assertEqual(expected_error, translated_error)
 
3798
 
2861
3799
 
2862
3800
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2863
3801
    """Unit tests for bzrlib.remote._translate_error's robustness.
2893
3831
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2894
3832
        # been muttered to the log file for developer to look at.
2895
3833
        self.assertContainsRe(
2896
 
            self._get_log(keep_log_file=True),
 
3834
            self.get_log(),
2897
3835
            "Missing key 'branch' in context")
2898
3836
 
2899
3837
    def test_path_missing(self):
2907
3845
        self.assertEqual(server_error, translated_error)
2908
3846
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2909
3847
        # been muttered to the log file for developer to look at.
2910
 
        self.assertContainsRe(
2911
 
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
 
3848
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
2912
3849
 
2913
3850
 
2914
3851
class TestStacking(tests.TestCaseWithTransport):
2932
3869
        stacked_branch = self.make_branch('stacked', format='1.9')
2933
3870
        stacked_branch.set_stacked_on_url('../base')
2934
3871
        # start a server looking at this
2935
 
        smart_server = server.SmartTCPServer_for_testing()
 
3872
        smart_server = test_server.SmartTCPServer_for_testing()
2936
3873
        self.start_server(smart_server)
2937
3874
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2938
3875
        # can get its branch and repository
3009
3946
        _, stacked = branch_factory()
3010
3947
        source = stacked.repository._get_source(target_repository_format)
3011
3948
        tip = stacked.last_revision()
3012
 
        revs = stacked.repository.get_ancestry(tip)
3013
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3949
        stacked.repository._ensure_real()
 
3950
        graph = stacked.repository.get_graph()
 
3951
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3952
                if r != NULL_REVISION]
 
3953
        revs.reverse()
 
3954
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3014
3955
        self.reset_smart_call_log()
3015
3956
        stream = source.get_stream(search)
3016
 
        if None in revs:
3017
 
            revs.remove(None)
3018
3957
        # We trust that if a revision is in the stream the rest of the new
3019
3958
        # content for it is too, as per our main fetch tests; here we are
3020
3959
        # checking that the revisions are actually included at all, and their
3042
3981
            local_tree.commit('more local changes are better')
3043
3982
            branch = Branch.open(self.get_url('tree3'))
3044
3983
            branch.lock_read()
 
3984
            self.addCleanup(branch.unlock)
3045
3985
            return None, branch
3046
3986
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
3047
3987
            branch_factory=make_stacked_stacked)
3058
3998
        self.assertEqual(expected_revs, rev_ord)
3059
3999
        # Getting topological sort requires VFS calls still - one of which is
3060
4000
        # pushing up from the bound branch.
3061
 
        self.assertLength(13, self.hpss_calls)
 
4001
        self.assertLength(14, self.hpss_calls)
3062
4002
 
3063
4003
    def test_stacked_get_stream_groupcompress(self):
3064
4004
        # Repository._get_source.get_stream() from a stacked repository with
3093
4033
        super(TestRemoteBranchEffort, self).setUp()
3094
4034
        # Create a smart server that publishes whatever the backing VFS server
3095
4035
        # does.
3096
 
        self.smart_server = server.SmartTCPServer_for_testing()
 
4036
        self.smart_server = test_server.SmartTCPServer_for_testing()
3097
4037
        self.start_server(self.smart_server, self.get_server())
3098
4038
        # Log all HPSS calls into self.hpss_calls.
3099
4039
        _SmartClient.hooks.install_named_hook(
3105
4045
 
3106
4046
    def test_copy_content_into_avoids_revision_history(self):
3107
4047
        local = self.make_branch('local')
3108
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3109
 
        remote_backing_tree.commit("Commit.")
 
4048
        builder = self.make_branch_builder('remote')
 
4049
        builder.build_commit(message="Commit.")
3110
4050
        remote_branch_url = self.smart_server.get_url() + 'remote'
3111
4051
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3112
4052
        local.repository.fetch(remote_branch.repository)
3113
4053
        self.hpss_calls = []
3114
4054
        remote_branch.copy_content_into(local)
3115
4055
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4056
 
 
4057
    def test_fetch_everything_needs_just_one_call(self):
 
4058
        local = self.make_branch('local')
 
4059
        builder = self.make_branch_builder('remote')
 
4060
        builder.build_commit(message="Commit.")
 
4061
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4062
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4063
        self.hpss_calls = []
 
4064
        local.repository.fetch(
 
4065
            remote_branch.repository,
 
4066
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4067
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4068
 
 
4069
    def override_verb(self, verb_name, verb):
 
4070
        request_handlers = request.request_handlers
 
4071
        orig_verb = request_handlers.get(verb_name)
 
4072
        orig_info = request_handlers.get_info(verb_name)
 
4073
        request_handlers.register(verb_name, verb, override_existing=True)
 
4074
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4075
                override_existing=True, info=orig_info)
 
4076
 
 
4077
    def test_fetch_everything_backwards_compat(self):
 
4078
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4079
        
 
4080
        Pre-2.4 do not support 'everything' searches with the
 
4081
        Repository.get_stream_1.19 verb.
 
4082
        """
 
4083
        verb_log = []
 
4084
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4085
            """A version of the Repository.get_stream_1.19 verb patched to
 
4086
            reject 'everything' searches the way 2.3 and earlier do.
 
4087
            """
 
4088
            def recreate_search(self, repository, search_bytes,
 
4089
                                discard_excess=False):
 
4090
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4091
                if search_bytes == 'everything':
 
4092
                    return (None,
 
4093
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4094
                return super(OldGetStreamVerb,
 
4095
                        self).recreate_search(repository, search_bytes,
 
4096
                            discard_excess=discard_excess)
 
4097
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4098
        local = self.make_branch('local')
 
4099
        builder = self.make_branch_builder('remote')
 
4100
        builder.build_commit(message="Commit.")
 
4101
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4102
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4103
        self.hpss_calls = []
 
4104
        local.repository.fetch(
 
4105
            remote_branch.repository,
 
4106
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4107
        # make sure the overridden verb was used
 
4108
        self.assertLength(1, verb_log)
 
4109
        # more than one HPSS call is needed, but because it's a VFS callback
 
4110
        # its hard to predict exactly how many.
 
4111
        self.assertTrue(len(self.hpss_calls) > 1)
 
4112
 
 
4113
 
 
4114
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4115
    tests.TestCaseWithTransport):
 
4116
    """Ensure correct handling of bound_location modifications.
 
4117
 
 
4118
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4119
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4120
    happen in this context.
 
4121
    """
 
4122
 
 
4123
    def setUp(self):
 
4124
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4125
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4126
 
 
4127
    def make_master_and_checkout(self, master_name, checkout_name):
 
4128
        # Create the master branch and its associated checkout
 
4129
        self.master = self.make_branch_and_tree(master_name)
 
4130
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4131
        # Modify the master branch so there is something to update
 
4132
        self.master.commit('add stuff')
 
4133
        self.last_revid = self.master.commit('even more stuff')
 
4134
        self.bound_location = self.checkout.branch.get_bound_location()
 
4135
 
 
4136
    def assertUpdateSucceeds(self, new_location):
 
4137
        self.checkout.branch.set_bound_location(new_location)
 
4138
        self.checkout.update()
 
4139
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4140
 
 
4141
    def test_without_final_slash(self):
 
4142
        self.make_master_and_checkout('master', 'checkout')
 
4143
        # For unclear reasons some users have a bound_location without a final
 
4144
        # '/', simulate that by forcing such a value
 
4145
        self.assertEndsWith(self.bound_location, '/')
 
4146
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4147
 
 
4148
    def test_plus_sign(self):
 
4149
        self.make_master_and_checkout('+master', 'checkout')
 
4150
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4151
 
 
4152
    def test_tilda(self):
 
4153
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4154
        # interpretation
 
4155
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4156
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4157
 
 
4158
 
 
4159
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4160
 
 
4161
    def test_no_context(self):
 
4162
        class OutOfCoffee(errors.BzrError):
 
4163
            """A dummy exception for testing."""
 
4164
 
 
4165
            def __init__(self, urgency):
 
4166
                self.urgency = urgency
 
4167
        remote.no_context_error_translators.register("OutOfCoffee",
 
4168
            lambda err: OutOfCoffee(err.error_args[0]))
 
4169
        transport = MemoryTransport()
 
4170
        client = FakeClient(transport.base)
 
4171
        client.add_expected_call(
 
4172
            'Branch.get_stacked_on_url', ('quack/',),
 
4173
            'error', ('NotStacked',))
 
4174
        client.add_expected_call(
 
4175
            'Branch.last_revision_info',
 
4176
            ('quack/',),
 
4177
            'error', ('OutOfCoffee', 'low'))
 
4178
        transport.mkdir('quack')
 
4179
        transport = transport.clone('quack')
 
4180
        branch = self.make_remote_branch(transport, client)
 
4181
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4182
        self.assertFinished(client)
 
4183
 
 
4184
    def test_with_context(self):
 
4185
        class OutOfTea(errors.BzrError):
 
4186
            def __init__(self, branch, urgency):
 
4187
                self.branch = branch
 
4188
                self.urgency = urgency
 
4189
        remote.error_translators.register("OutOfTea",
 
4190
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4191
                find("branch")))
 
4192
        transport = MemoryTransport()
 
4193
        client = FakeClient(transport.base)
 
4194
        client.add_expected_call(
 
4195
            'Branch.get_stacked_on_url', ('quack/',),
 
4196
            'error', ('NotStacked',))
 
4197
        client.add_expected_call(
 
4198
            'Branch.last_revision_info',
 
4199
            ('quack/',),
 
4200
            'error', ('OutOfTea', 'low'))
 
4201
        transport.mkdir('quack')
 
4202
        transport = transport.clone('quack')
 
4203
        branch = self.make_remote_branch(transport, client)
 
4204
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4205
        self.assertFinished(client)
 
4206
 
 
4207
 
 
4208
class TestRepositoryPack(TestRemoteRepository):
 
4209
 
 
4210
    def test_pack(self):
 
4211
        transport_path = 'quack'
 
4212
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4213
        client.add_expected_call(
 
4214
            'Repository.lock_write', ('quack/', ''),
 
4215
            'success', ('ok', 'token'))
 
4216
        client.add_expected_call(
 
4217
            'Repository.pack', ('quack/', 'token', 'False'),
 
4218
            'success', ('ok',), )
 
4219
        client.add_expected_call(
 
4220
            'Repository.unlock', ('quack/', 'token'),
 
4221
            'success', ('ok', ))
 
4222
        repo.pack()
 
4223
 
 
4224
    def test_pack_with_hint(self):
 
4225
        transport_path = 'quack'
 
4226
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4227
        client.add_expected_call(
 
4228
            'Repository.lock_write', ('quack/', ''),
 
4229
            'success', ('ok', 'token'))
 
4230
        client.add_expected_call(
 
4231
            'Repository.pack', ('quack/', 'token', 'False'),
 
4232
            'success', ('ok',), )
 
4233
        client.add_expected_call(
 
4234
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4235
            'success', ('ok', ))
 
4236
        repo.pack(['hinta', 'hintb'])
 
4237
 
 
4238
 
 
4239
class TestRepositoryIterInventories(TestRemoteRepository):
 
4240
    """Test Repository.iter_inventories."""
 
4241
 
 
4242
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4243
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4244
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4245
 
 
4246
    def test_single_empty(self):
 
4247
        transport_path = 'quack'
 
4248
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4249
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4250
        repo._format = fmt
 
4251
        stream = [('inventory-deltas', [
 
4252
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4253
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4254
        client.add_expected_call(
 
4255
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4256
            'success', ('ok', ),
 
4257
            _stream_to_byte_stream(stream, fmt))
 
4258
        ret = list(repo.iter_inventories(["somerevid"]))
 
4259
        self.assertLength(1, ret)
 
4260
        inv = ret[0]
 
4261
        self.assertEquals("somerevid", inv.revision_id)
 
4262
 
 
4263
    def test_empty(self):
 
4264
        transport_path = 'quack'
 
4265
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4266
        ret = list(repo.iter_inventories([]))
 
4267
        self.assertEquals(ret, [])
 
4268
 
 
4269
    def test_missing(self):
 
4270
        transport_path = 'quack'
 
4271
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4272
        client.add_expected_call(
 
4273
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4274
            'success', ('ok', ), iter([]))
 
4275
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4276
            ["somerevid"]))