~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: INADA Naoki
  • Date: 2011-05-18 06:27:34 UTC
  • mfrom: (5887 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5894.
  • Revision ID: songofacandy@gmail.com-20110518062734-1ilhll0rrqyyp8um
merge from lp:bzr and resolve conflicts.

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
27
27
from cStringIO import StringIO
28
28
 
29
29
from bzrlib import (
 
30
    branch,
30
31
    bzrdir,
31
32
    config,
 
33
    controldir,
32
34
    errors,
33
35
    graph,
34
36
    inventory,
35
37
    inventory_delta,
36
 
    pack,
37
38
    remote,
38
39
    repository,
39
 
    smart,
40
40
    tests,
 
41
    transport,
41
42
    treebuilder,
42
 
    urlutils,
43
43
    versionedfile,
44
44
    )
45
45
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
46
from bzrlib.bzrdir import (
 
47
    BzrDir,
 
48
    BzrDirFormat,
 
49
    RemoteBzrProber,
 
50
    )
47
51
from bzrlib.remote import (
48
52
    RemoteBranch,
49
53
    RemoteBranchFormat,
52
56
    RemoteRepository,
53
57
    RemoteRepositoryFormat,
54
58
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
 
59
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
56
60
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import server, medium
 
61
from bzrlib.smart import medium, request
58
62
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
63
from bzrlib.smart.repository import (
 
64
    SmartServerRepositoryGetParentMap,
 
65
    SmartServerRepositoryGetStream_1_19,
 
66
    )
60
67
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
 
    KnownFailure,
 
68
    test_server,
65
69
    )
66
 
from bzrlib.transport import get_transport, http
 
70
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
71
from bzrlib.transport.memory import MemoryTransport
68
72
from bzrlib.transport.remote import (
69
73
    RemoteTransport,
70
74
    RemoteSSHTransport,
71
75
    RemoteTCPTransport,
72
 
)
73
 
 
74
 
def load_tests(standard_tests, module, loader):
75
 
    to_adapt, result = split_suite_by_condition(
76
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
 
    smart_server_version_scenarios = [
 
76
    )
 
77
 
 
78
 
 
79
load_tests = load_tests_apply_scenarios
 
80
 
 
81
 
 
82
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
83
 
 
84
    scenarios = [
78
85
        ('HPSS-v2',
79
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
 
86
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
87
        ('HPSS-v3',
81
 
            {'transport_server': server.SmartTCPServer_for_testing})]
82
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
83
 
 
84
 
 
85
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
88
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
89
 
86
90
 
87
91
    def setUp(self):
88
92
        super(BasicRemoteObjectTests, self).setUp()
89
93
        self.transport = self.get_transport()
90
94
        # make a branch that can be opened over the smart transport
91
95
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
96
        self.addCleanup(self.transport.disconnect)
96
97
 
97
98
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
99
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
100
        self.assertIsInstance(b, BzrDir)
100
101
 
101
102
    def test_open_remote_branch(self):
102
103
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
104
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
105
        branch = b.open_branch()
105
106
        self.assertIsInstance(branch, Branch)
106
107
 
122
123
    def test_find_correct_format(self):
123
124
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
125
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
126
        self.assertTrue(bzrdir.RemoteBzrProber
 
127
                        in controldir.ControlDirFormat._server_probers)
 
128
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
129
 
129
130
    def test_open_detected_smart_format(self):
130
131
        fmt = BzrDirFormat.find_format(self.transport)
135
136
        b = BzrDir.open_from_transport(self.transport).open_branch()
136
137
        self.assertStartsWith(str(b), 'RemoteBranch(')
137
138
 
 
139
    def test_remote_bzrdir_repr(self):
 
140
        b = BzrDir.open_from_transport(self.transport)
 
141
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
 
142
 
138
143
    def test_remote_branch_format_supports_stacking(self):
139
144
        t = self.transport
140
145
        self.make_branch('unstackable', format='pack-0.92')
280
285
        self.expecting_body = True
281
286
        return result[1], FakeProtocol(result[2], self)
282
287
 
 
288
    def call_with_body_bytes(self, method, args, body):
 
289
        self._check_call(method, args)
 
290
        self._calls.append(('call_with_body_bytes', method, args, body))
 
291
        result = self._get_next_response()
 
292
        return result[1], FakeProtocol(result[2], self)
 
293
 
283
294
    def call_with_body_bytes_expecting_body(self, method, args, body):
284
295
        self._check_call(method, args)
285
296
        self._calls.append(('call_with_body_bytes_expecting_body', method,
349
360
        a given client_base and transport_base.
350
361
        """
351
362
        client_medium = medium.SmartClientMedium(client_base)
352
 
        transport = get_transport(transport_base)
353
 
        result = client_medium.remote_path_from_transport(transport)
 
363
        t = transport.get_transport(transport_base)
 
364
        result = client_medium.remote_path_from_transport(t)
354
365
        self.assertEqual(expected, result)
355
366
 
356
367
    def test_remote_path_from_transport(self):
367
378
        a given transport_base and relpath of that transport.  (Note that
368
379
        HttpTransportBase is a subclass of SmartClientMedium)
369
380
        """
370
 
        base_transport = get_transport(transport_base)
 
381
        base_transport = transport.get_transport(transport_base)
371
382
        client_medium = base_transport.get_smart_medium()
372
383
        cloned_transport = base_transport.clone(relpath)
373
384
        result = client_medium.remote_path_from_transport(cloned_transport)
408
419
        # Calling _remember_remote_is_before again with a lower value works.
409
420
        client_medium._remember_remote_is_before((1, 5))
410
421
        self.assertTrue(client_medium._is_remote_before((1, 5)))
411
 
        # You cannot call _remember_remote_is_before with a larger value.
412
 
        self.assertRaises(
413
 
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
 
422
        # If you call _remember_remote_is_before with a higher value it logs a
 
423
        # warning, and continues to remember the lower value.
 
424
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
 
425
        client_medium._remember_remote_is_before((1, 9))
 
426
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
 
427
        self.assertTrue(client_medium._is_remote_before((1, 5)))
414
428
 
415
429
 
416
430
class TestBzrDirCloningMetaDir(TestRemote):
435
449
            'BzrDir.cloning_metadir', ('quack/', 'False'),
436
450
            'error', ('BranchReference',)),
437
451
        client.add_expected_call(
438
 
            'BzrDir.open_branchV2', ('quack/',),
 
452
            'BzrDir.open_branchV3', ('quack/',),
439
453
            'success', ('ref', self.get_url('referenced'))),
440
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
454
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
441
455
            _client=client)
442
456
        result = a_bzrdir.cloning_metadir()
443
457
        # We should have got a control dir matching the referenced branch.
456
470
        client.add_expected_call(
457
471
            'BzrDir.cloning_metadir', ('quack/', 'False'),
458
472
            'success', (control_name, '', ('branch', ''))),
459
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
473
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
460
474
            _client=client)
461
475
        result = a_bzrdir.cloning_metadir()
462
476
        # We should have got a reference control dir with default branch and
468
482
        self.assertFinished(client)
469
483
 
470
484
 
 
485
class TestBzrDirOpen(TestRemote):
 
486
 
 
487
    def make_fake_client_and_transport(self, path='quack'):
 
488
        transport = MemoryTransport()
 
489
        transport.mkdir(path)
 
490
        transport = transport.clone(path)
 
491
        client = FakeClient(transport.base)
 
492
        return client, transport
 
493
 
 
494
    def test_absent(self):
 
495
        client, transport = self.make_fake_client_and_transport()
 
496
        client.add_expected_call(
 
497
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
 
498
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
 
499
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
500
        self.assertFinished(client)
 
501
 
 
502
    def test_present_without_workingtree(self):
 
503
        client, transport = self.make_fake_client_and_transport()
 
504
        client.add_expected_call(
 
505
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
 
506
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
507
            _client=client, _force_probe=True)
 
508
        self.assertIsInstance(bd, RemoteBzrDir)
 
509
        self.assertFalse(bd.has_workingtree())
 
510
        self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
 
511
        self.assertFinished(client)
 
512
 
 
513
    def test_present_with_workingtree(self):
 
514
        client, transport = self.make_fake_client_and_transport()
 
515
        client.add_expected_call(
 
516
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
 
517
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
518
            _client=client, _force_probe=True)
 
519
        self.assertIsInstance(bd, RemoteBzrDir)
 
520
        self.assertTrue(bd.has_workingtree())
 
521
        self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
 
522
        self.assertFinished(client)
 
523
 
 
524
    def test_backwards_compat(self):
 
525
        client, transport = self.make_fake_client_and_transport()
 
526
        client.add_expected_call(
 
527
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
528
        client.add_expected_call(
 
529
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
530
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
531
            _client=client, _force_probe=True)
 
532
        self.assertIsInstance(bd, RemoteBzrDir)
 
533
        self.assertFinished(client)
 
534
 
 
535
    def test_backwards_compat_hpss_v2(self):
 
536
        client, transport = self.make_fake_client_and_transport()
 
537
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
538
        # server: upon first RPC call detect the protocol version, and because
 
539
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
540
        # continuing with the RPC.
 
541
        orig_check_call = client._check_call
 
542
        def check_call(method, args):
 
543
            client._medium._protocol_version = 2
 
544
            client._medium._remember_remote_is_before((1, 6))
 
545
            client._check_call = orig_check_call
 
546
            client._check_call(method, args)
 
547
        client._check_call = check_call
 
548
        client.add_expected_call(
 
549
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
550
        client.add_expected_call(
 
551
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
552
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
553
            _client=client, _force_probe=True)
 
554
        self.assertIsInstance(bd, RemoteBzrDir)
 
555
        self.assertFinished(client)
 
556
 
 
557
 
471
558
class TestBzrDirOpenBranch(TestRemote):
472
559
 
473
560
    def test_backwards_compat(self):
475
562
        self.make_branch('.')
476
563
        a_dir = BzrDir.open(self.get_url('.'))
477
564
        self.reset_smart_call_log()
478
 
        verb = 'BzrDir.open_branchV2'
 
565
        verb = 'BzrDir.open_branchV3'
479
566
        self.disable_verb(verb)
480
567
        format = a_dir.open_branch()
481
568
        call_count = len([call for call in self.hpss_calls if
491
578
        transport = transport.clone('quack')
492
579
        client = FakeClient(transport.base)
493
580
        client.add_expected_call(
494
 
            'BzrDir.open_branchV2', ('quack/',),
 
581
            'BzrDir.open_branchV3', ('quack/',),
495
582
            'success', ('branch', branch_network_name))
496
583
        client.add_expected_call(
497
584
            'BzrDir.find_repositoryV3', ('quack/',),
499
586
        client.add_expected_call(
500
587
            'Branch.get_stacked_on_url', ('quack/',),
501
588
            'error', ('NotStacked',))
502
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
589
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
503
590
            _client=client)
504
591
        result = bzrdir.open_branch()
505
592
        self.assertIsInstance(result, RemoteBranch)
512
599
        transport = transport.clone('quack')
513
600
        client = FakeClient(transport.base)
514
601
        client.add_error_response('nobranch')
515
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
602
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
516
603
            _client=client)
517
604
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
518
605
        self.assertEqual(
519
 
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
 
606
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
520
607
            client._calls)
521
608
 
522
609
    def test__get_tree_branch(self):
523
610
        # _get_tree_branch is a form of open_branch, but it should only ask for
524
611
        # branch opening, not any other network requests.
525
612
        calls = []
526
 
        def open_branch():
 
613
        def open_branch(name=None):
527
614
            calls.append("Called")
528
615
            return "a-branch"
529
616
        transport = MemoryTransport()
530
617
        # no requests on the network - catches other api calls being made.
531
618
        client = FakeClient(transport.base)
532
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
619
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
533
620
            _client=client)
534
621
        # patch the open_branch call to record that it was called.
535
622
        bzrdir.open_branch = open_branch
546
633
        network_name = reference_format.network_name()
547
634
        branch_network_name = self.get_branch_format().network_name()
548
635
        client.add_expected_call(
549
 
            'BzrDir.open_branchV2', ('~hello/',),
 
636
            'BzrDir.open_branchV3', ('~hello/',),
550
637
            'success', ('branch', branch_network_name))
551
638
        client.add_expected_call(
552
639
            'BzrDir.find_repositoryV3', ('~hello/',),
554
641
        client.add_expected_call(
555
642
            'Branch.get_stacked_on_url', ('~hello/',),
556
643
            'error', ('NotStacked',))
557
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
644
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
558
645
            _client=client)
559
646
        result = bzrdir.open_branch()
560
647
        self.assertFinished(client)
577
664
        client.add_success_response(
578
665
            'ok', '', rich_response, subtree_response, external_lookup,
579
666
            network_name)
580
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
667
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
581
668
            _client=client)
582
669
        result = bzrdir.open_repository()
583
670
        self.assertEqual(
600
687
        old.
601
688
        """
602
689
        self.assertRaises(errors.NotBranchError,
603
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
690
            RemoteBzrProber.probe_transport, OldServerTransport())
604
691
 
605
692
 
606
693
class TestBzrDirCreateBranch(TestRemote):
629
716
            'BzrDir.create_branch', ('quack/', network_name),
630
717
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
631
718
            reference_repo_name))
632
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
719
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
633
720
            _client=client)
634
721
        branch = a_bzrdir.create_branch()
635
722
        # We should have got a remote branch
638
725
        format = branch._format
639
726
        self.assertEqual(network_name, format.network_name())
640
727
 
 
728
    def test_already_open_repo_and_reused_medium(self):
 
729
        """Bug 726584: create_branch(..., repository=repo) should work
 
730
        regardless of what the smart medium's base URL is.
 
731
        """
 
732
        self.transport_server = test_server.SmartTCPServer_for_testing
 
733
        transport = self.get_transport('.')
 
734
        repo = self.make_repository('quack')
 
735
        # Client's medium rooted a transport root (not at the bzrdir)
 
736
        client = FakeClient(transport.base)
 
737
        transport = transport.clone('quack')
 
738
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
739
        reference_format = reference_bzrdir_format.get_branch_format()
 
740
        network_name = reference_format.network_name()
 
741
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
742
        reference_repo_name = reference_repo_fmt.network_name()
 
743
        client.add_expected_call(
 
744
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
745
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
746
            reference_repo_name))
 
747
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
748
            _client=client)
 
749
        branch = a_bzrdir.create_branch(repository=repo)
 
750
        # We should have got a remote branch
 
751
        self.assertIsInstance(branch, remote.RemoteBranch)
 
752
        # its format should have the settings from the response
 
753
        format = branch._format
 
754
        self.assertEqual(network_name, format.network_name())
 
755
 
641
756
 
642
757
class TestBzrDirCreateRepository(TestRemote):
643
758
 
664
779
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
665
780
                'False'),
666
781
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
667
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
782
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
783
            _client=client)
669
784
        repo = a_bzrdir.create_repository()
670
785
        # We should have got a remote repository
683
798
        # fallback all the way to the first version.
684
799
        reference_format = self.get_repo_format()
685
800
        network_name = reference_format.network_name()
686
 
        client = FakeClient('bzr://example.com/')
 
801
        server_url = 'bzr://example.com/'
 
802
        self.permit_url(server_url)
 
803
        client = FakeClient(server_url)
687
804
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
688
805
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
689
806
        client.add_success_response('ok', '', 'no', 'no')
695
812
            reference_format.get_format_string(), 'ok')
696
813
        # PackRepository wants to do a stat
697
814
        client.add_success_response('stat', '0', '65535')
698
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
815
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
699
816
            _client=client)
700
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
817
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
701
818
            _client=client)
702
819
        repo = bzrdir.open_repository()
703
820
        self.assertEqual(
715
832
        # fallback to find_repositoryV2
716
833
        reference_format = self.get_repo_format()
717
834
        network_name = reference_format.network_name()
718
 
        client = FakeClient('bzr://example.com/')
 
835
        server_url = 'bzr://example.com/'
 
836
        self.permit_url(server_url)
 
837
        client = FakeClient(server_url)
719
838
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
720
839
        client.add_success_response('ok', '', 'no', 'no', 'no')
721
840
        # A real repository instance will be created to determine the network
726
845
            reference_format.get_format_string(), 'ok')
727
846
        # PackRepository wants to do a stat
728
847
        client.add_success_response('stat', '0', '65535')
729
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
848
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
730
849
            _client=client)
731
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
850
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
732
851
            _client=client)
733
852
        repo = bzrdir.open_repository()
734
853
        self.assertEqual(
749
868
        transport = transport.clone('quack')
750
869
        client = FakeClient(transport.base)
751
870
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
752
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
871
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
753
872
            _client=client)
754
873
        repo = bzrdir.open_repository()
755
874
        self.assertEqual(
762
881
 
763
882
    def test_success(self):
764
883
        """Simple test for typical successful call."""
765
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
884
        fmt = RemoteBzrDirFormat()
766
885
        default_format_name = BzrDirFormat.get_default_format().network_name()
767
886
        transport = self.get_transport()
768
887
        client = FakeClient(transport.base)
784
903
        """Error responses are translated, e.g. 'PermissionDenied' raises the
785
904
        corresponding error from the client.
786
905
        """
787
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
906
        fmt = RemoteBzrDirFormat()
788
907
        default_format_name = BzrDirFormat.get_default_format().network_name()
789
908
        transport = self.get_transport()
790
909
        client = FakeClient(transport.base)
808
927
        """Integration test for error translation."""
809
928
        transport = self.make_smart_server('foo')
810
929
        transport = transport.clone('no-such-path')
811
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
930
        fmt = RemoteBzrDirFormat()
812
931
        err = self.assertRaises(errors.NoSuchFile,
813
932
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
814
933
 
845
964
 
846
965
    def make_remote_bzrdir(self, transport, client):
847
966
        """Make a RemotebzrDir using 'client' as the _client."""
848
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
967
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
849
968
            _client=client)
850
969
 
851
970
 
852
971
class RemoteBranchTestCase(RemoteBzrDirTestCase):
853
972
 
 
973
    def lock_remote_branch(self, branch):
 
974
        """Trick a RemoteBranch into thinking it is locked."""
 
975
        branch._lock_mode = 'w'
 
976
        branch._lock_count = 2
 
977
        branch._lock_token = 'branch token'
 
978
        branch._repo_lock_token = 'repo token'
 
979
        branch.repository._lock_mode = 'w'
 
980
        branch.repository._lock_count = 2
 
981
        branch.repository._lock_token = 'repo token'
 
982
 
854
983
    def make_remote_branch(self, transport, client):
855
984
        """Make a RemoteBranch using 'client' as its _SmartClient.
856
985
 
995
1124
        self.assertEqual({}, result)
996
1125
 
997
1126
 
 
1127
class TestBranchSetTagsBytes(RemoteBranchTestCase):
 
1128
 
 
1129
    def test_trivial(self):
 
1130
        transport = MemoryTransport()
 
1131
        client = FakeClient(transport.base)
 
1132
        client.add_expected_call(
 
1133
            'Branch.get_stacked_on_url', ('quack/',),
 
1134
            'error', ('NotStacked',))
 
1135
        client.add_expected_call(
 
1136
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1137
            'success', ('',))
 
1138
        transport.mkdir('quack')
 
1139
        transport = transport.clone('quack')
 
1140
        branch = self.make_remote_branch(transport, client)
 
1141
        self.lock_remote_branch(branch)
 
1142
        branch._set_tags_bytes('tags bytes')
 
1143
        self.assertFinished(client)
 
1144
        self.assertEqual('tags bytes', client._calls[-1][-1])
 
1145
 
 
1146
    def test_backwards_compatible(self):
 
1147
        transport = MemoryTransport()
 
1148
        client = FakeClient(transport.base)
 
1149
        client.add_expected_call(
 
1150
            'Branch.get_stacked_on_url', ('quack/',),
 
1151
            'error', ('NotStacked',))
 
1152
        client.add_expected_call(
 
1153
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1154
            'unknown', ('Branch.set_tags_bytes',))
 
1155
        transport.mkdir('quack')
 
1156
        transport = transport.clone('quack')
 
1157
        branch = self.make_remote_branch(transport, client)
 
1158
        self.lock_remote_branch(branch)
 
1159
        class StubRealBranch(object):
 
1160
            def __init__(self):
 
1161
                self.calls = []
 
1162
            def _set_tags_bytes(self, bytes):
 
1163
                self.calls.append(('set_tags_bytes', bytes))
 
1164
        real_branch = StubRealBranch()
 
1165
        branch._real_branch = real_branch
 
1166
        branch._set_tags_bytes('tags bytes')
 
1167
        # Call a second time, to exercise the 'remote version already inferred'
 
1168
        # code path.
 
1169
        branch._set_tags_bytes('tags bytes')
 
1170
        self.assertFinished(client)
 
1171
        self.assertEqual(
 
1172
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
 
1173
 
 
1174
 
 
1175
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1176
 
 
1177
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1178
        transport = MemoryTransport()
 
1179
        client = FakeClient(transport.base)
 
1180
        client.add_expected_call(
 
1181
            'Branch.get_stacked_on_url', ('quack/',),
 
1182
            'error', ('NotStacked',))
 
1183
        client.add_expected_call(
 
1184
            'Branch.last_revision_info', ('quack/',),
 
1185
            'success', ('ok', '1', 'rev-tip'))
 
1186
        # XXX: this will break if the default format's serialization of tags
 
1187
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1188
        client.add_expected_call(
 
1189
            'Branch.get_tags_bytes', ('quack/',),
 
1190
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1191
        transport.mkdir('quack')
 
1192
        transport = transport.clone('quack')
 
1193
        branch = self.make_remote_branch(transport, client)
 
1194
        result = branch.heads_to_fetch()
 
1195
        self.assertFinished(client)
 
1196
        self.assertEqual(
 
1197
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1198
 
 
1199
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1200
        transport = MemoryTransport()
 
1201
        client = FakeClient(transport.base)
 
1202
        client.add_expected_call(
 
1203
            'Branch.get_stacked_on_url', ('quack/',),
 
1204
            'error', ('NotStacked',))
 
1205
        client.add_expected_call(
 
1206
            'Branch.heads_to_fetch', ('quack/',),
 
1207
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1208
        transport.mkdir('quack')
 
1209
        transport = transport.clone('quack')
 
1210
        branch = self.make_remote_branch(transport, client)
 
1211
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1212
        result = branch.heads_to_fetch()
 
1213
        self.assertFinished(client)
 
1214
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1215
 
 
1216
    def test_backwards_compatible(self):
 
1217
        self.setup_smart_server_with_call_log()
 
1218
        # Make a branch with a single revision.
 
1219
        builder = self.make_branch_builder('foo')
 
1220
        builder.start_series()
 
1221
        builder.build_snapshot('tip', None, [
 
1222
            ('add', ('', 'root-id', 'directory', ''))])
 
1223
        builder.finish_series()
 
1224
        branch = builder.get_branch()
 
1225
        # Add two tags to that branch
 
1226
        branch.tags.set_tag('tag-1', 'rev-1')
 
1227
        branch.tags.set_tag('tag-2', 'rev-2')
 
1228
        self.addCleanup(branch.lock_read().unlock)
 
1229
        # Disable the heads_to_fetch verb
 
1230
        verb = 'Branch.heads_to_fetch'
 
1231
        self.disable_verb(verb)
 
1232
        self.reset_smart_call_log()
 
1233
        result = branch.heads_to_fetch()
 
1234
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1235
        self.assertEqual(
 
1236
            ['Branch.last_revision_info', 'Branch.get_tags_bytes'],
 
1237
            [call.call.method for call in self.hpss_calls])
 
1238
 
 
1239
 
998
1240
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
999
1241
 
1000
1242
    def test_empty_branch(self):
1055
1297
        client.add_expected_call(
1056
1298
            'Branch.get_stacked_on_url', ('stacked/',),
1057
1299
            'success', ('ok', vfs_url))
1058
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1300
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1059
1301
            _client=client)
1060
1302
        repo_fmt = remote.RemoteRepositoryFormat()
1061
1303
        repo_fmt._custom_format = stacked_branch.repository._format
1072
1314
        client = FakeClient(self.get_url())
1073
1315
        branch_network_name = self.get_branch_format().network_name()
1074
1316
        client.add_expected_call(
1075
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1317
            'BzrDir.open_branchV3', ('stacked/',),
1076
1318
            'success', ('branch', branch_network_name))
1077
1319
        client.add_expected_call(
1078
1320
            'BzrDir.find_repositoryV3', ('stacked/',),
1088
1330
        # this will also do vfs access, but that goes direct to the transport
1089
1331
        # and isn't seen by the FakeClient.
1090
1332
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1091
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1333
            RemoteBzrDirFormat(), _client=client)
1092
1334
        branch = bzrdir.open_branch()
1093
1335
        result = branch.get_stacked_on_url()
1094
1336
        self.assertEqual('../base', result)
1100
1342
            len(branch.repository._real_repository._fallback_repositories))
1101
1343
 
1102
1344
    def test_get_stacked_on_real_branch(self):
1103
 
        base_branch = self.make_branch('base', format='1.6')
1104
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1345
        base_branch = self.make_branch('base')
 
1346
        stacked_branch = self.make_branch('stacked')
1105
1347
        stacked_branch.set_stacked_on_url('../base')
1106
1348
        reference_format = self.get_repo_format()
1107
1349
        network_name = reference_format.network_name()
1108
1350
        client = FakeClient(self.get_url())
1109
1351
        branch_network_name = self.get_branch_format().network_name()
1110
1352
        client.add_expected_call(
1111
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1353
            'BzrDir.open_branchV3', ('stacked/',),
1112
1354
            'success', ('branch', branch_network_name))
1113
1355
        client.add_expected_call(
1114
1356
            'BzrDir.find_repositoryV3', ('stacked/',),
1115
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1357
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1116
1358
        # called twice, once from constructor and then again by us
1117
1359
        client.add_expected_call(
1118
1360
            'Branch.get_stacked_on_url', ('stacked/',),
1121
1363
            'Branch.get_stacked_on_url', ('stacked/',),
1122
1364
            'success', ('ok', '../base'))
1123
1365
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1124
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1366
            RemoteBzrDirFormat(), _client=client)
1125
1367
        branch = bzrdir.open_branch()
1126
1368
        result = branch.get_stacked_on_url()
1127
1369
        self.assertEqual('../base', result)
1135
1377
class TestBranchSetLastRevision(RemoteBranchTestCase):
1136
1378
 
1137
1379
    def test_set_empty(self):
1138
 
        # set_revision_history([]) is translated to calling
 
1380
        # _set_last_revision_info('null:') is translated to calling
1139
1381
        # Branch.set_last_revision(path, '') on the wire.
1140
1382
        transport = MemoryTransport()
1141
1383
        transport.mkdir('branch')
1163
1405
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1164
1406
        branch._ensure_real = lambda: None
1165
1407
        branch.lock_write()
1166
 
        result = branch.set_revision_history([])
 
1408
        result = branch._set_last_revision(NULL_REVISION)
1167
1409
        branch.unlock()
1168
1410
        self.assertEqual(None, result)
1169
1411
        self.assertFinished(client)
1170
1412
 
1171
1413
    def test_set_nonempty(self):
1172
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1414
        # set_last_revision_info(N, rev-idN) is translated to calling
1173
1415
        # Branch.set_last_revision(path, rev-idN) on the wire.
1174
1416
        transport = MemoryTransport()
1175
1417
        transport.mkdir('branch')
1201
1443
        branch._ensure_real = lambda: None
1202
1444
        # Lock the branch, reset the record of remote calls.
1203
1445
        branch.lock_write()
1204
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1446
        result = branch._set_last_revision('rev-id2')
1205
1447
        branch.unlock()
1206
1448
        self.assertEqual(None, result)
1207
1449
        self.assertFinished(client)
1237
1479
        branch = self.make_remote_branch(transport, client)
1238
1480
        branch.lock_write()
1239
1481
        self.assertRaises(
1240
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1482
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1241
1483
        branch.unlock()
1242
1484
        self.assertFinished(client)
1243
1485
 
1274
1516
        branch._ensure_real = lambda: None
1275
1517
        branch.lock_write()
1276
1518
        # The 'TipChangeRejected' error response triggered by calling
1277
 
        # set_revision_history causes a TipChangeRejected exception.
 
1519
        # set_last_revision_info causes a TipChangeRejected exception.
1278
1520
        err = self.assertRaises(
1279
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1521
            errors.TipChangeRejected,
 
1522
            branch._set_last_revision, 'rev-id')
1280
1523
        # The UTF-8 message from the response has been decoded into a unicode
1281
1524
        # object.
1282
1525
        self.assertIsInstance(err.msg, unicode)
1342
1585
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1343
1586
        branch.unlock()
1344
1587
 
1345
 
    def lock_remote_branch(self, branch):
1346
 
        """Trick a RemoteBranch into thinking it is locked."""
1347
 
        branch._lock_mode = 'w'
1348
 
        branch._lock_count = 2
1349
 
        branch._lock_token = 'branch token'
1350
 
        branch._repo_lock_token = 'repo token'
1351
 
        branch.repository._lock_mode = 'w'
1352
 
        branch.repository._lock_count = 2
1353
 
        branch.repository._lock_token = 'repo token'
1354
 
 
1355
1588
    def test_backwards_compatibility(self):
1356
1589
        """If the server does not support the Branch.set_last_revision_info
1357
1590
        verb (which is new in 1.4), then the client falls back to VFS methods.
1480
1713
    def test_get_multi_line_branch_conf(self):
1481
1714
        # Make sure that multiple-line branch.conf files are supported
1482
1715
        #
1483
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1716
        # https://bugs.launchpad.net/bzr/+bug/354075
1484
1717
        client = FakeClient()
1485
1718
        client.add_expected_call(
1486
1719
            'Branch.get_stacked_on_url', ('memory:///',),
1514
1747
        branch.unlock()
1515
1748
        self.assertFinished(client)
1516
1749
 
 
1750
    def test_set_option_with_dict(self):
 
1751
        client = FakeClient()
 
1752
        client.add_expected_call(
 
1753
            'Branch.get_stacked_on_url', ('memory:///',),
 
1754
            'error', ('NotStacked',),)
 
1755
        client.add_expected_call(
 
1756
            'Branch.lock_write', ('memory:///', '', ''),
 
1757
            'success', ('ok', 'branch token', 'repo token'))
 
1758
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1759
        client.add_expected_call(
 
1760
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1761
            'repo token', encoded_dict_value, 'foo', ''),
 
1762
            'success', ())
 
1763
        client.add_expected_call(
 
1764
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1765
            'success', ('ok',))
 
1766
        transport = MemoryTransport()
 
1767
        branch = self.make_remote_branch(transport, client)
 
1768
        branch.lock_write()
 
1769
        config = branch._get_config()
 
1770
        config.set_option(
 
1771
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1772
            'foo')
 
1773
        branch.unlock()
 
1774
        self.assertFinished(client)
 
1775
 
1517
1776
    def test_backwards_compat_set_option(self):
1518
1777
        self.setup_smart_server_with_call_log()
1519
1778
        branch = self.make_branch('.')
1526
1785
        self.assertLength(10, self.hpss_calls)
1527
1786
        self.assertEqual('value', branch._get_config().get_option('name'))
1528
1787
 
 
1788
    def test_backwards_compat_set_option_with_dict(self):
 
1789
        self.setup_smart_server_with_call_log()
 
1790
        branch = self.make_branch('.')
 
1791
        verb = 'Branch.set_config_option_dict'
 
1792
        self.disable_verb(verb)
 
1793
        branch.lock_write()
 
1794
        self.addCleanup(branch.unlock)
 
1795
        self.reset_smart_call_log()
 
1796
        config = branch._get_config()
 
1797
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
1798
        config.set_option(value_dict, 'name')
 
1799
        self.assertLength(10, self.hpss_calls)
 
1800
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
1801
 
1529
1802
 
1530
1803
class TestBranchLockWrite(RemoteBranchTestCase):
1531
1804
 
1667
1940
        client = FakeClient(transport.base)
1668
1941
        transport = transport.clone(transport_path)
1669
1942
        # we do not want bzrdir to make any remote calls
1670
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1943
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1671
1944
            _client=False)
1672
1945
        repo = RemoteRepository(bzrdir, None, _client=client)
1673
1946
        return repo, client
1674
1947
 
1675
1948
 
 
1949
def remoted_description(format):
 
1950
    return 'Remote: ' + format.get_format_description()
 
1951
 
 
1952
 
 
1953
class TestBranchFormat(tests.TestCase):
 
1954
 
 
1955
    def test_get_format_description(self):
 
1956
        remote_format = RemoteBranchFormat()
 
1957
        real_format = branch.format_registry.get_default()
 
1958
        remote_format._network_name = real_format.network_name()
 
1959
        self.assertEqual(remoted_description(real_format),
 
1960
            remote_format.get_format_description())
 
1961
 
 
1962
 
1676
1963
class TestRepositoryFormat(TestRemoteRepository):
1677
1964
 
1678
1965
    def test_fast_delta(self):
1679
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
1966
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1680
1967
        true_format = RemoteRepositoryFormat()
1681
1968
        true_format._network_name = true_name
1682
1969
        self.assertEqual(True, true_format.fast_deltas)
1683
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
1970
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1684
1971
        false_format = RemoteRepositoryFormat()
1685
1972
        false_format._network_name = false_name
1686
1973
        self.assertEqual(False, false_format.fast_deltas)
1687
1974
 
 
1975
    def test_get_format_description(self):
 
1976
        remote_repo_format = RemoteRepositoryFormat()
 
1977
        real_format = repository.format_registry.get_default()
 
1978
        remote_repo_format._network_name = real_format.network_name()
 
1979
        self.assertEqual(remoted_description(real_format),
 
1980
            remote_repo_format.get_format_description())
 
1981
 
1688
1982
 
1689
1983
class TestRepositoryGatherStats(TestRemoteRepository):
1690
1984
 
1875
2169
        self.assertLength(1, self.hpss_calls)
1876
2170
 
1877
2171
    def disableExtraResults(self):
1878
 
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
1879
 
        SmartServerRepositoryGetParentMap.no_extra_results = True
1880
 
        def reset_values():
1881
 
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
1882
 
        self.addCleanup(reset_values)
 
2172
        self.overrideAttr(SmartServerRepositoryGetParentMap,
 
2173
                          'no_extra_results', True)
1883
2174
 
1884
2175
    def test_null_cached_missing_and_stop_key(self):
1885
2176
        self.setup_smart_server_with_call_log()
1944
2235
 
1945
2236
    def test_allows_new_revisions(self):
1946
2237
        """get_parent_map's results can be updated by commit."""
1947
 
        smart_server = server.SmartTCPServer_for_testing()
1948
 
        smart_server.setUp()
1949
 
        self.addCleanup(smart_server.tearDown)
 
2238
        smart_server = test_server.SmartTCPServer_for_testing()
 
2239
        self.start_server(smart_server)
1950
2240
        self.make_branch('branch')
1951
2241
        branch = Branch.open(smart_server.get_url() + '/branch')
1952
2242
        tree = branch.create_checkout('tree', lightweight=True)
2061
2351
        """
2062
2352
        # Make a repo with a fallback repo, both using a FakeClient.
2063
2353
        format = remote.response_tuple_to_repo_format(
2064
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2354
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2065
2355
        repo, client = self.setup_fake_client_and_repository('quack')
2066
2356
        repo._format = format
2067
2357
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2068
2358
            'fallback')
2069
2359
        fallback_repo._client = client
 
2360
        fallback_repo._format = format
2070
2361
        repo.add_fallback_repository(fallback_repo)
2071
2362
        # First the client should ask the primary repo
2072
2363
        client.add_expected_call(
2093
2384
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2094
2385
        self.assertFinished(client)
2095
2386
 
 
2387
    def test_branch_fallback_locking(self):
 
2388
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
 
2389
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
 
2390
        will be invoked, which will fail if the repo is unlocked.
 
2391
        """
 
2392
        self.setup_smart_server_with_call_log()
 
2393
        tree = self.make_branch_and_memory_tree('.')
 
2394
        tree.lock_write()
 
2395
        tree.add('')
 
2396
        rev1 = tree.commit('First')
 
2397
        rev2 = tree.commit('Second')
 
2398
        tree.unlock()
 
2399
        branch = tree.branch
 
2400
        self.assertFalse(branch.is_locked())
 
2401
        self.reset_smart_call_log()
 
2402
        verb = 'Repository.get_rev_id_for_revno'
 
2403
        self.disable_verb(verb)
 
2404
        self.assertEqual(rev1, branch.get_rev_id(1))
 
2405
        self.assertLength(1, [call for call in self.hpss_calls if
 
2406
                              call.call.method == verb])
 
2407
 
2096
2408
 
2097
2409
class TestRepositoryIsShared(TestRemoteRepository):
2098
2410
 
2125
2437
        transport_path = 'quack'
2126
2438
        repo, client = self.setup_fake_client_and_repository(transport_path)
2127
2439
        client.add_success_response('ok', 'a token')
2128
 
        result = repo.lock_write()
 
2440
        token = repo.lock_write().repository_token
2129
2441
        self.assertEqual(
2130
2442
            [('call', 'Repository.lock_write', ('quack/', ''))],
2131
2443
            client._calls)
2132
 
        self.assertEqual('a token', result)
 
2444
        self.assertEqual('a token', token)
2133
2445
 
2134
2446
    def test_lock_write_already_locked(self):
2135
2447
        transport_path = 'quack'
2226
2538
        the client is finished.
2227
2539
        """
2228
2540
        sink = repo._get_sink()
2229
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2541
        fmt = repository.format_registry.get_default()
2230
2542
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2231
2543
        self.assertEqual([], resume_tokens)
2232
2544
        self.assertEqual(set(), missing_keys)
2326
2638
        class FakeRealRepository:
2327
2639
            def _get_sink(self):
2328
2640
                return fake_real_sink
 
2641
            def is_in_write_group(self):
 
2642
                return False
 
2643
            def refresh_data(self):
 
2644
                return True
2329
2645
        repo._real_repository = FakeRealRepository()
2330
2646
        sink = repo._get_sink()
2331
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2647
        fmt = repository.format_registry.get_default()
2332
2648
        stream = self.make_stream_with_inv_deltas(fmt)
2333
2649
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2334
2650
        # Every record from the first inventory delta should have been sent to
2469
2785
    """RemoteRepository.copy_content_into optimizations"""
2470
2786
 
2471
2787
    def test_copy_content_remote_to_local(self):
2472
 
        self.transport_server = server.SmartTCPServer_for_testing
 
2788
        self.transport_server = test_server.SmartTCPServer_for_testing
2473
2789
        src_repo = self.make_repository('repo1')
2474
2790
        src_repo = repository.Repository.open(self.get_url('repo1'))
2475
2791
        # At the moment the tarball-based copy_content_into can't write back
2554
2870
             ('pack collection autopack',)],
2555
2871
            client._calls)
2556
2872
 
 
2873
    def test_oom_error_reporting(self):
 
2874
        """An out-of-memory condition on the server is reported clearly"""
 
2875
        transport_path = 'quack'
 
2876
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2877
        client.add_expected_call(
 
2878
            'PackRepository.autopack', ('quack/',),
 
2879
            'error', ('MemoryError',))
 
2880
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
2881
        self.assertContainsRe(str(err), "^remote server out of mem")
 
2882
 
2557
2883
 
2558
2884
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2559
2885
    """Base class for unit tests for bzrlib.remote._translate_error."""
2623
2949
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2624
2950
        self.assertEqual(expected_error, translated_error)
2625
2951
 
 
2952
    def test_nobranch_one_arg(self):
 
2953
        bzrdir = self.make_bzrdir('')
 
2954
        translated_error = self.translateTuple(
 
2955
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
 
2956
        expected_error = errors.NotBranchError(
 
2957
            path=bzrdir.root_transport.base,
 
2958
            detail='extra detail')
 
2959
        self.assertEqual(expected_error, translated_error)
 
2960
 
 
2961
    def test_norepository(self):
 
2962
        bzrdir = self.make_bzrdir('')
 
2963
        translated_error = self.translateTuple(('norepository',),
 
2964
            bzrdir=bzrdir)
 
2965
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
2966
        self.assertEqual(expected_error, translated_error)
 
2967
 
2626
2968
    def test_LockContention(self):
2627
2969
        translated_error = self.translateTuple(('LockContention',))
2628
2970
        expected_error = errors.LockContention('(remote lock)')
2656
2998
        expected_error = errors.DivergedBranches(branch, other_branch)
2657
2999
        self.assertEqual(expected_error, translated_error)
2658
3000
 
 
3001
    def test_NotStacked(self):
 
3002
        branch = self.make_branch('')
 
3003
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3004
        expected_error = errors.NotStacked(branch)
 
3005
        self.assertEqual(expected_error, translated_error)
 
3006
 
2659
3007
    def test_ReadError_no_args(self):
2660
3008
        path = 'a path'
2661
3009
        translated_error = self.translateTuple(('ReadError',), path=path)
2668
3016
        expected_error = errors.ReadError(path)
2669
3017
        self.assertEqual(expected_error, translated_error)
2670
3018
 
 
3019
    def test_IncompatibleRepositories(self):
 
3020
        translated_error = self.translateTuple(('IncompatibleRepositories',
 
3021
            "repo1", "repo2", "details here"))
 
3022
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
 
3023
            "details here")
 
3024
        self.assertEqual(expected_error, translated_error)
 
3025
 
2671
3026
    def test_PermissionDenied_no_args(self):
2672
3027
        path = 'a path'
2673
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3028
        translated_error = self.translateTuple(('PermissionDenied',),
 
3029
            path=path)
2674
3030
        expected_error = errors.PermissionDenied(path)
2675
3031
        self.assertEqual(expected_error, translated_error)
2676
3032
 
2699
3055
        expected_error = errors.PermissionDenied(path, extra)
2700
3056
        self.assertEqual(expected_error, translated_error)
2701
3057
 
 
3058
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3059
 
 
3060
    def test_NoSuchFile_context_path(self):
 
3061
        local_path = "local path"
 
3062
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3063
            path=local_path)
 
3064
        expected_error = errors.ReadError(local_path)
 
3065
        self.assertEqual(expected_error, translated_error)
 
3066
 
 
3067
    def test_NoSuchFile_without_context(self):
 
3068
        remote_path = "remote path"
 
3069
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3070
        expected_error = errors.ReadError(remote_path)
 
3071
        self.assertEqual(expected_error, translated_error)
 
3072
 
 
3073
    def test_ReadOnlyError(self):
 
3074
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3075
        expected_error = errors.TransportNotPossible("readonly transport")
 
3076
        self.assertEqual(expected_error, translated_error)
 
3077
 
 
3078
    def test_MemoryError(self):
 
3079
        translated_error = self.translateTuple(('MemoryError',))
 
3080
        self.assertStartsWith(str(translated_error),
 
3081
            "remote server out of memory")
 
3082
 
 
3083
    def test_generic_IndexError_no_classname(self):
 
3084
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3085
        translated_error = self.translateErrorFromSmartServer(err)
 
3086
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3087
        self.assertEqual(expected_error, translated_error)
 
3088
 
 
3089
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3090
 
 
3091
    def test_generic_KeyError(self):
 
3092
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3093
        translated_error = self.translateErrorFromSmartServer(err)
 
3094
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3095
        self.assertEqual(expected_error, translated_error)
 
3096
 
2702
3097
 
2703
3098
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2704
3099
    """Unit tests for bzrlib.remote._translate_error's robustness.
2734
3129
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2735
3130
        # been muttered to the log file for developer to look at.
2736
3131
        self.assertContainsRe(
2737
 
            self._get_log(keep_log_file=True),
 
3132
            self.get_log(),
2738
3133
            "Missing key 'branch' in context")
2739
3134
 
2740
3135
    def test_path_missing(self):
2748
3143
        self.assertEqual(server_error, translated_error)
2749
3144
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2750
3145
        # been muttered to the log file for developer to look at.
2751
 
        self.assertContainsRe(
2752
 
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
 
3146
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
2753
3147
 
2754
3148
 
2755
3149
class TestStacking(tests.TestCaseWithTransport):
2773
3167
        stacked_branch = self.make_branch('stacked', format='1.9')
2774
3168
        stacked_branch.set_stacked_on_url('../base')
2775
3169
        # start a server looking at this
2776
 
        smart_server = server.SmartTCPServer_for_testing()
2777
 
        smart_server.setUp()
2778
 
        self.addCleanup(smart_server.tearDown)
 
3170
        smart_server = test_server.SmartTCPServer_for_testing()
 
3171
        self.start_server(smart_server)
2779
3172
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2780
3173
        # can get its branch and repository
2781
3174
        remote_branch = remote_bzrdir.open_branch()
2884
3277
            local_tree.commit('more local changes are better')
2885
3278
            branch = Branch.open(self.get_url('tree3'))
2886
3279
            branch.lock_read()
 
3280
            self.addCleanup(branch.unlock)
2887
3281
            return None, branch
2888
3282
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
2889
3283
            branch_factory=make_stacked_stacked)
2935
3329
        super(TestRemoteBranchEffort, self).setUp()
2936
3330
        # Create a smart server that publishes whatever the backing VFS server
2937
3331
        # does.
2938
 
        self.smart_server = server.SmartTCPServer_for_testing()
2939
 
        self.smart_server.setUp(self.get_server())
2940
 
        self.addCleanup(self.smart_server.tearDown)
 
3332
        self.smart_server = test_server.SmartTCPServer_for_testing()
 
3333
        self.start_server(self.smart_server, self.get_server())
2941
3334
        # Log all HPSS calls into self.hpss_calls.
2942
3335
        _SmartClient.hooks.install_named_hook(
2943
3336
            'call', self.capture_hpss_call, None)
2948
3341
 
2949
3342
    def test_copy_content_into_avoids_revision_history(self):
2950
3343
        local = self.make_branch('local')
2951
 
        remote_backing_tree = self.make_branch_and_tree('remote')
2952
 
        remote_backing_tree.commit("Commit.")
 
3344
        builder = self.make_branch_builder('remote')
 
3345
        builder.build_commit(message="Commit.")
2953
3346
        remote_branch_url = self.smart_server.get_url() + 'remote'
2954
3347
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
2955
3348
        local.repository.fetch(remote_branch.repository)
2956
3349
        self.hpss_calls = []
2957
3350
        remote_branch.copy_content_into(local)
2958
3351
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
3352
 
 
3353
    def test_fetch_everything_needs_just_one_call(self):
 
3354
        local = self.make_branch('local')
 
3355
        builder = self.make_branch_builder('remote')
 
3356
        builder.build_commit(message="Commit.")
 
3357
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3358
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3359
        self.hpss_calls = []
 
3360
        local.repository.fetch(remote_branch.repository,
 
3361
                fetch_spec=graph.EverythingResult(remote_branch.repository))
 
3362
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
3363
 
 
3364
    def override_verb(self, verb_name, verb):
 
3365
        request_handlers = request.request_handlers
 
3366
        orig_verb = request_handlers.get(verb_name)
 
3367
        request_handlers.register(verb_name, verb, override_existing=True)
 
3368
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
3369
                override_existing=True)
 
3370
 
 
3371
    def test_fetch_everything_backwards_compat(self):
 
3372
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
3373
        
 
3374
        Pre-2.4 do not support 'everything' searches with the
 
3375
        Repository.get_stream_1.19 verb.
 
3376
        """
 
3377
        verb_log = []
 
3378
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
3379
            """A version of the Repository.get_stream_1.19 verb patched to
 
3380
            reject 'everything' searches the way 2.3 and earlier do.
 
3381
            """
 
3382
            def recreate_search(self, repository, search_bytes, discard_excess=False):
 
3383
                verb_log.append(search_bytes.split('\n', 1)[0])
 
3384
                if search_bytes == 'everything':
 
3385
                    return (None, request.FailedSmartServerResponse(('BadSearch',)))
 
3386
                return super(OldGetStreamVerb,
 
3387
                        self).recreate_search(repository, search_bytes,
 
3388
                            discard_excess=discard_excess)
 
3389
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
3390
        local = self.make_branch('local')
 
3391
        builder = self.make_branch_builder('remote')
 
3392
        builder.build_commit(message="Commit.")
 
3393
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3394
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3395
        self.hpss_calls = []
 
3396
        local.repository.fetch(remote_branch.repository,
 
3397
                fetch_spec=graph.EverythingResult(remote_branch.repository))
 
3398
        # make sure the overridden verb was used
 
3399
        self.assertLength(1, verb_log)
 
3400
        # more than one HPSS call is needed, but because it's a VFS callback
 
3401
        # its hard to predict exactly how many.
 
3402
        self.assertTrue(len(self.hpss_calls) > 1)
 
3403