~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Andrew Bennetts
  • Date: 2009-08-07 04:17:51 UTC
  • mto: This revision was merged to the branch mainline in revision 4608.
  • Revision ID: andrew.bennetts@canonical.com-20090807041751-0vhb0y0g7k49hr45
Review comments from John.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008, 2009 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,
31
30
    bzrdir,
32
31
    config,
33
 
    controldir,
34
32
    errors,
35
 
    graph as _mod_graph,
 
33
    graph,
36
34
    inventory,
37
35
    inventory_delta,
 
36
    pack,
38
37
    remote,
39
38
    repository,
 
39
    smart,
40
40
    tests,
41
 
    transport,
42
41
    treebuilder,
 
42
    urlutils,
43
43
    versionedfile,
44
44
    )
45
45
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import (
47
 
    BzrDir,
48
 
    BzrDirFormat,
49
 
    RemoteBzrProber,
50
 
    )
 
46
from bzrlib.bzrdir import BzrDir, BzrDirFormat
51
47
from bzrlib.remote import (
52
48
    RemoteBranch,
53
49
    RemoteBranchFormat,
56
52
    RemoteRepository,
57
53
    RemoteRepositoryFormat,
58
54
    )
59
 
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
 
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
60
56
from bzrlib.revision import NULL_REVISION
61
 
from bzrlib.smart import medium, request
 
57
from bzrlib.smart import server, medium
62
58
from bzrlib.smart.client import _SmartClient
63
 
from bzrlib.smart.repository import (
64
 
    SmartServerRepositoryGetParentMap,
65
 
    SmartServerRepositoryGetStream_1_19,
66
 
    )
 
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
67
60
from bzrlib.tests import (
68
 
    test_server,
 
61
    condition_isinstance,
 
62
    split_suite_by_condition,
 
63
    multiply_tests,
 
64
    KnownFailure,
69
65
    )
70
 
from bzrlib.tests.scenarios import load_tests_apply_scenarios
 
66
from bzrlib.transport import get_transport, http
71
67
from bzrlib.transport.memory import MemoryTransport
72
68
from bzrlib.transport.remote import (
73
69
    RemoteTransport,
74
70
    RemoteSSHTransport,
75
71
    RemoteTCPTransport,
76
 
    )
77
 
 
78
 
 
79
 
load_tests = load_tests_apply_scenarios
80
 
 
81
 
 
82
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
83
 
 
84
 
    scenarios = [
 
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 = [
85
78
        ('HPSS-v2',
86
 
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
79
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
87
80
        ('HPSS-v3',
88
 
            {'transport_server': test_server.SmartTCPServer_for_testing})]
89
 
 
 
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):
90
86
 
91
87
    def setUp(self):
92
88
        super(BasicRemoteObjectTests, self).setUp()
93
89
        self.transport = self.get_transport()
94
90
        # make a branch that can be opened over the smart transport
95
91
        self.local_wt = BzrDir.create_standalone_workingtree('.')
96
 
        self.addCleanup(self.transport.disconnect)
 
92
 
 
93
    def tearDown(self):
 
94
        self.transport.disconnect()
 
95
        tests.TestCaseWithTransport.tearDown(self)
97
96
 
98
97
    def test_create_remote_bzrdir(self):
99
 
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
 
98
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
100
99
        self.assertIsInstance(b, BzrDir)
101
100
 
102
101
    def test_open_remote_branch(self):
103
102
        # open a standalone branch in the working directory
104
 
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
 
103
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
105
104
        branch = b.open_branch()
106
105
        self.assertIsInstance(branch, Branch)
107
106
 
123
122
    def test_find_correct_format(self):
124
123
        """Should open a RemoteBzrDir over a RemoteTransport"""
125
124
        fmt = BzrDirFormat.find_format(self.transport)
126
 
        self.assertTrue(bzrdir.RemoteBzrProber
127
 
                        in controldir.ControlDirFormat._server_probers)
128
 
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
 
125
        self.assertTrue(RemoteBzrDirFormat
 
126
                        in BzrDirFormat._control_server_formats)
 
127
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
129
128
 
130
129
    def test_open_detected_smart_format(self):
131
130
        fmt = BzrDirFormat.find_format(self.transport)
136
135
        b = BzrDir.open_from_transport(self.transport).open_branch()
137
136
        self.assertStartsWith(str(b), 'RemoteBranch(')
138
137
 
139
 
    def test_remote_bzrdir_repr(self):
140
 
        b = BzrDir.open_from_transport(self.transport)
141
 
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
142
 
 
143
138
    def test_remote_branch_format_supports_stacking(self):
144
139
        t = self.transport
145
140
        self.make_branch('unstackable', format='pack-0.92')
285
280
        self.expecting_body = True
286
281
        return result[1], FakeProtocol(result[2], self)
287
282
 
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
 
 
294
283
    def call_with_body_bytes_expecting_body(self, method, args, body):
295
284
        self._check_call(method, args)
296
285
        self._calls.append(('call_with_body_bytes_expecting_body', method,
360
349
        a given client_base and transport_base.
361
350
        """
362
351
        client_medium = medium.SmartClientMedium(client_base)
363
 
        t = transport.get_transport(transport_base)
364
 
        result = client_medium.remote_path_from_transport(t)
 
352
        transport = get_transport(transport_base)
 
353
        result = client_medium.remote_path_from_transport(transport)
365
354
        self.assertEqual(expected, result)
366
355
 
367
356
    def test_remote_path_from_transport(self):
378
367
        a given transport_base and relpath of that transport.  (Note that
379
368
        HttpTransportBase is a subclass of SmartClientMedium)
380
369
        """
381
 
        base_transport = transport.get_transport(transport_base)
 
370
        base_transport = get_transport(transport_base)
382
371
        client_medium = base_transport.get_smart_medium()
383
372
        cloned_transport = base_transport.clone(relpath)
384
373
        result = client_medium.remote_path_from_transport(cloned_transport)
419
408
        # Calling _remember_remote_is_before again with a lower value works.
420
409
        client_medium._remember_remote_is_before((1, 5))
421
410
        self.assertTrue(client_medium._is_remote_before((1, 5)))
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)))
 
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))
428
414
 
429
415
 
430
416
class TestBzrDirCloningMetaDir(TestRemote):
449
435
            'BzrDir.cloning_metadir', ('quack/', 'False'),
450
436
            'error', ('BranchReference',)),
451
437
        client.add_expected_call(
452
 
            'BzrDir.open_branchV3', ('quack/',),
 
438
            'BzrDir.open_branchV2', ('quack/',),
453
439
            'success', ('ref', self.get_url('referenced'))),
454
 
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
440
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
455
441
            _client=client)
456
442
        result = a_bzrdir.cloning_metadir()
457
443
        # We should have got a control dir matching the referenced branch.
470
456
        client.add_expected_call(
471
457
            'BzrDir.cloning_metadir', ('quack/', 'False'),
472
458
            'success', (control_name, '', ('branch', ''))),
473
 
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
459
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
474
460
            _client=client)
475
461
        result = a_bzrdir.cloning_metadir()
476
462
        # We should have got a reference control dir with default branch and
482
468
        self.assertFinished(client)
483
469
 
484
470
 
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
 
 
558
471
class TestBzrDirOpenBranch(TestRemote):
559
472
 
560
473
    def test_backwards_compat(self):
562
475
        self.make_branch('.')
563
476
        a_dir = BzrDir.open(self.get_url('.'))
564
477
        self.reset_smart_call_log()
565
 
        verb = 'BzrDir.open_branchV3'
 
478
        verb = 'BzrDir.open_branchV2'
566
479
        self.disable_verb(verb)
567
480
        format = a_dir.open_branch()
568
481
        call_count = len([call for call in self.hpss_calls if
578
491
        transport = transport.clone('quack')
579
492
        client = FakeClient(transport.base)
580
493
        client.add_expected_call(
581
 
            'BzrDir.open_branchV3', ('quack/',),
 
494
            'BzrDir.open_branchV2', ('quack/',),
582
495
            'success', ('branch', branch_network_name))
583
496
        client.add_expected_call(
584
497
            'BzrDir.find_repositoryV3', ('quack/',),
586
499
        client.add_expected_call(
587
500
            'Branch.get_stacked_on_url', ('quack/',),
588
501
            'error', ('NotStacked',))
589
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
502
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
590
503
            _client=client)
591
504
        result = bzrdir.open_branch()
592
505
        self.assertIsInstance(result, RemoteBranch)
599
512
        transport = transport.clone('quack')
600
513
        client = FakeClient(transport.base)
601
514
        client.add_error_response('nobranch')
602
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
515
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
603
516
            _client=client)
604
517
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
605
518
        self.assertEqual(
606
 
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
 
519
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
607
520
            client._calls)
608
521
 
609
522
    def test__get_tree_branch(self):
610
523
        # _get_tree_branch is a form of open_branch, but it should only ask for
611
524
        # branch opening, not any other network requests.
612
525
        calls = []
613
 
        def open_branch(name=None):
 
526
        def open_branch():
614
527
            calls.append("Called")
615
528
            return "a-branch"
616
529
        transport = MemoryTransport()
617
530
        # no requests on the network - catches other api calls being made.
618
531
        client = FakeClient(transport.base)
619
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
532
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
620
533
            _client=client)
621
534
        # patch the open_branch call to record that it was called.
622
535
        bzrdir.open_branch = open_branch
633
546
        network_name = reference_format.network_name()
634
547
        branch_network_name = self.get_branch_format().network_name()
635
548
        client.add_expected_call(
636
 
            'BzrDir.open_branchV3', ('~hello/',),
 
549
            'BzrDir.open_branchV2', ('~hello/',),
637
550
            'success', ('branch', branch_network_name))
638
551
        client.add_expected_call(
639
552
            'BzrDir.find_repositoryV3', ('~hello/',),
641
554
        client.add_expected_call(
642
555
            'Branch.get_stacked_on_url', ('~hello/',),
643
556
            'error', ('NotStacked',))
644
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
557
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
645
558
            _client=client)
646
559
        result = bzrdir.open_branch()
647
560
        self.assertFinished(client)
664
577
        client.add_success_response(
665
578
            'ok', '', rich_response, subtree_response, external_lookup,
666
579
            network_name)
667
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
580
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
668
581
            _client=client)
669
582
        result = bzrdir.open_repository()
670
583
        self.assertEqual(
687
600
        old.
688
601
        """
689
602
        self.assertRaises(errors.NotBranchError,
690
 
            RemoteBzrProber.probe_transport, OldServerTransport())
 
603
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
691
604
 
692
605
 
693
606
class TestBzrDirCreateBranch(TestRemote):
716
629
            'BzrDir.create_branch', ('quack/', network_name),
717
630
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
718
631
            reference_repo_name))
719
 
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
632
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
633
            _client=client)
721
634
        branch = a_bzrdir.create_branch()
722
635
        # We should have got a remote branch
725
638
        format = branch._format
726
639
        self.assertEqual(network_name, format.network_name())
727
640
 
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
 
 
756
641
 
757
642
class TestBzrDirCreateRepository(TestRemote):
758
643
 
776
661
        network_name = reference_format.network_name()
777
662
        client.add_expected_call(
778
663
            'BzrDir.create_repository', ('quack/',
779
 
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
780
 
                'False'),
781
 
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
782
 
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
664
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
 
665
            'success', ('ok', 'no', 'no', 'no', network_name))
 
666
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
783
667
            _client=client)
784
668
        repo = a_bzrdir.create_repository()
785
669
        # We should have got a remote repository
786
670
        self.assertIsInstance(repo, remote.RemoteRepository)
787
671
        # its format should have the settings from the response
788
672
        format = repo._format
789
 
        self.assertTrue(format.rich_root_data)
790
 
        self.assertTrue(format.supports_tree_reference)
791
 
        self.assertTrue(format.supports_external_lookups)
 
673
        self.assertFalse(format.rich_root_data)
 
674
        self.assertFalse(format.supports_tree_reference)
 
675
        self.assertFalse(format.supports_external_lookups)
792
676
        self.assertEqual(network_name, format.network_name())
793
677
 
794
678
 
798
682
        # fallback all the way to the first version.
799
683
        reference_format = self.get_repo_format()
800
684
        network_name = reference_format.network_name()
801
 
        server_url = 'bzr://example.com/'
802
 
        self.permit_url(server_url)
803
 
        client = FakeClient(server_url)
 
685
        client = FakeClient('bzr://example.com/')
804
686
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
805
687
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
806
688
        client.add_success_response('ok', '', 'no', 'no')
812
694
            reference_format.get_format_string(), 'ok')
813
695
        # PackRepository wants to do a stat
814
696
        client.add_success_response('stat', '0', '65535')
815
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
697
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
816
698
            _client=client)
817
 
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
 
699
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
818
700
            _client=client)
819
701
        repo = bzrdir.open_repository()
820
702
        self.assertEqual(
832
714
        # fallback to find_repositoryV2
833
715
        reference_format = self.get_repo_format()
834
716
        network_name = reference_format.network_name()
835
 
        server_url = 'bzr://example.com/'
836
 
        self.permit_url(server_url)
837
 
        client = FakeClient(server_url)
 
717
        client = FakeClient('bzr://example.com/')
838
718
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
839
719
        client.add_success_response('ok', '', 'no', 'no', 'no')
840
720
        # A real repository instance will be created to determine the network
845
725
            reference_format.get_format_string(), 'ok')
846
726
        # PackRepository wants to do a stat
847
727
        client.add_success_response('stat', '0', '65535')
848
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
728
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
849
729
            _client=client)
850
 
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
 
730
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
851
731
            _client=client)
852
732
        repo = bzrdir.open_repository()
853
733
        self.assertEqual(
868
748
        transport = transport.clone('quack')
869
749
        client = FakeClient(transport.base)
870
750
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
871
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
751
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
872
752
            _client=client)
873
753
        repo = bzrdir.open_repository()
874
754
        self.assertEqual(
881
761
 
882
762
    def test_success(self):
883
763
        """Simple test for typical successful call."""
884
 
        fmt = RemoteBzrDirFormat()
 
764
        fmt = bzrdir.RemoteBzrDirFormat()
885
765
        default_format_name = BzrDirFormat.get_default_format().network_name()
886
766
        transport = self.get_transport()
887
767
        client = FakeClient(transport.base)
903
783
        """Error responses are translated, e.g. 'PermissionDenied' raises the
904
784
        corresponding error from the client.
905
785
        """
906
 
        fmt = RemoteBzrDirFormat()
 
786
        fmt = bzrdir.RemoteBzrDirFormat()
907
787
        default_format_name = BzrDirFormat.get_default_format().network_name()
908
788
        transport = self.get_transport()
909
789
        client = FakeClient(transport.base)
927
807
        """Integration test for error translation."""
928
808
        transport = self.make_smart_server('foo')
929
809
        transport = transport.clone('no-such-path')
930
 
        fmt = RemoteBzrDirFormat()
 
810
        fmt = bzrdir.RemoteBzrDirFormat()
931
811
        err = self.assertRaises(errors.NoSuchFile,
932
812
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
933
813
 
964
844
 
965
845
    def make_remote_bzrdir(self, transport, client):
966
846
        """Make a RemotebzrDir using 'client' as the _client."""
967
 
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
847
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
968
848
            _client=client)
969
849
 
970
850
 
971
851
class RemoteBranchTestCase(RemoteBzrDirTestCase):
972
852
 
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
 
 
983
853
    def make_remote_branch(self, transport, client):
984
854
        """Make a RemoteBranch using 'client' as its _SmartClient.
985
855
 
1124
994
        self.assertEqual({}, result)
1125
995
 
1126
996
 
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
 
 
1240
997
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1241
998
 
1242
999
    def test_empty_branch(self):
1297
1054
        client.add_expected_call(
1298
1055
            'Branch.get_stacked_on_url', ('stacked/',),
1299
1056
            'success', ('ok', vfs_url))
1300
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
1057
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1301
1058
            _client=client)
1302
1059
        repo_fmt = remote.RemoteRepositoryFormat()
1303
1060
        repo_fmt._custom_format = stacked_branch.repository._format
1314
1071
        client = FakeClient(self.get_url())
1315
1072
        branch_network_name = self.get_branch_format().network_name()
1316
1073
        client.add_expected_call(
1317
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1074
            'BzrDir.open_branchV2', ('stacked/',),
1318
1075
            'success', ('branch', branch_network_name))
1319
1076
        client.add_expected_call(
1320
1077
            'BzrDir.find_repositoryV3', ('stacked/',),
1330
1087
        # this will also do vfs access, but that goes direct to the transport
1331
1088
        # and isn't seen by the FakeClient.
1332
1089
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1333
 
            RemoteBzrDirFormat(), _client=client)
 
1090
            remote.RemoteBzrDirFormat(), _client=client)
1334
1091
        branch = bzrdir.open_branch()
1335
1092
        result = branch.get_stacked_on_url()
1336
1093
        self.assertEqual('../base', result)
1342
1099
            len(branch.repository._real_repository._fallback_repositories))
1343
1100
 
1344
1101
    def test_get_stacked_on_real_branch(self):
1345
 
        base_branch = self.make_branch('base')
1346
 
        stacked_branch = self.make_branch('stacked')
 
1102
        base_branch = self.make_branch('base', format='1.6')
 
1103
        stacked_branch = self.make_branch('stacked', format='1.6')
1347
1104
        stacked_branch.set_stacked_on_url('../base')
1348
1105
        reference_format = self.get_repo_format()
1349
1106
        network_name = reference_format.network_name()
1350
1107
        client = FakeClient(self.get_url())
1351
1108
        branch_network_name = self.get_branch_format().network_name()
1352
1109
        client.add_expected_call(
1353
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1110
            'BzrDir.open_branchV2', ('stacked/',),
1354
1111
            'success', ('branch', branch_network_name))
1355
1112
        client.add_expected_call(
1356
1113
            'BzrDir.find_repositoryV3', ('stacked/',),
1357
 
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
 
1114
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
1358
1115
        # called twice, once from constructor and then again by us
1359
1116
        client.add_expected_call(
1360
1117
            'Branch.get_stacked_on_url', ('stacked/',),
1363
1120
            'Branch.get_stacked_on_url', ('stacked/',),
1364
1121
            'success', ('ok', '../base'))
1365
1122
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1366
 
            RemoteBzrDirFormat(), _client=client)
 
1123
            remote.RemoteBzrDirFormat(), _client=client)
1367
1124
        branch = bzrdir.open_branch()
1368
1125
        result = branch.get_stacked_on_url()
1369
1126
        self.assertEqual('../base', result)
1377
1134
class TestBranchSetLastRevision(RemoteBranchTestCase):
1378
1135
 
1379
1136
    def test_set_empty(self):
1380
 
        # _set_last_revision_info('null:') is translated to calling
 
1137
        # set_revision_history([]) is translated to calling
1381
1138
        # Branch.set_last_revision(path, '') on the wire.
1382
1139
        transport = MemoryTransport()
1383
1140
        transport.mkdir('branch')
1405
1162
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1406
1163
        branch._ensure_real = lambda: None
1407
1164
        branch.lock_write()
1408
 
        result = branch._set_last_revision(NULL_REVISION)
 
1165
        result = branch.set_revision_history([])
1409
1166
        branch.unlock()
1410
1167
        self.assertEqual(None, result)
1411
1168
        self.assertFinished(client)
1412
1169
 
1413
1170
    def test_set_nonempty(self):
1414
 
        # set_last_revision_info(N, rev-idN) is translated to calling
 
1171
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1415
1172
        # Branch.set_last_revision(path, rev-idN) on the wire.
1416
1173
        transport = MemoryTransport()
1417
1174
        transport.mkdir('branch')
1443
1200
        branch._ensure_real = lambda: None
1444
1201
        # Lock the branch, reset the record of remote calls.
1445
1202
        branch.lock_write()
1446
 
        result = branch._set_last_revision('rev-id2')
 
1203
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1447
1204
        branch.unlock()
1448
1205
        self.assertEqual(None, result)
1449
1206
        self.assertFinished(client)
1479
1236
        branch = self.make_remote_branch(transport, client)
1480
1237
        branch.lock_write()
1481
1238
        self.assertRaises(
1482
 
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
 
1239
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1483
1240
        branch.unlock()
1484
1241
        self.assertFinished(client)
1485
1242
 
1516
1273
        branch._ensure_real = lambda: None
1517
1274
        branch.lock_write()
1518
1275
        # The 'TipChangeRejected' error response triggered by calling
1519
 
        # set_last_revision_info causes a TipChangeRejected exception.
 
1276
        # set_revision_history causes a TipChangeRejected exception.
1520
1277
        err = self.assertRaises(
1521
 
            errors.TipChangeRejected,
1522
 
            branch._set_last_revision, 'rev-id')
 
1278
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1523
1279
        # The UTF-8 message from the response has been decoded into a unicode
1524
1280
        # object.
1525
1281
        self.assertIsInstance(err.msg, unicode)
1585
1341
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1586
1342
        branch.unlock()
1587
1343
 
 
1344
    def lock_remote_branch(self, branch):
 
1345
        """Trick a RemoteBranch into thinking it is locked."""
 
1346
        branch._lock_mode = 'w'
 
1347
        branch._lock_count = 2
 
1348
        branch._lock_token = 'branch token'
 
1349
        branch._repo_lock_token = 'repo token'
 
1350
        branch.repository._lock_mode = 'w'
 
1351
        branch.repository._lock_count = 2
 
1352
        branch.repository._lock_token = 'repo token'
 
1353
 
1588
1354
    def test_backwards_compatibility(self):
1589
1355
        """If the server does not support the Branch.set_last_revision_info
1590
1356
        verb (which is new in 1.4), then the client falls back to VFS methods.
1713
1479
    def test_get_multi_line_branch_conf(self):
1714
1480
        # Make sure that multiple-line branch.conf files are supported
1715
1481
        #
1716
 
        # https://bugs.launchpad.net/bzr/+bug/354075
 
1482
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1717
1483
        client = FakeClient()
1718
1484
        client.add_expected_call(
1719
1485
            'Branch.get_stacked_on_url', ('memory:///',),
1747
1513
        branch.unlock()
1748
1514
        self.assertFinished(client)
1749
1515
 
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
 
 
1776
1516
    def test_backwards_compat_set_option(self):
1777
1517
        self.setup_smart_server_with_call_log()
1778
1518
        branch = self.make_branch('.')
1785
1525
        self.assertLength(10, self.hpss_calls)
1786
1526
        self.assertEqual('value', branch._get_config().get_option('name'))
1787
1527
 
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
 
 
1802
1528
 
1803
1529
class TestBranchLockWrite(RemoteBranchTestCase):
1804
1530
 
1940
1666
        client = FakeClient(transport.base)
1941
1667
        transport = transport.clone(transport_path)
1942
1668
        # we do not want bzrdir to make any remote calls
1943
 
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
1669
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1944
1670
            _client=False)
1945
1671
        repo = RemoteRepository(bzrdir, None, _client=client)
1946
1672
        return repo, client
1947
1673
 
1948
1674
 
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
 
 
1963
1675
class TestRepositoryFormat(TestRemoteRepository):
1964
1676
 
1965
1677
    def test_fast_delta(self):
1966
 
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
 
1678
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
1967
1679
        true_format = RemoteRepositoryFormat()
1968
1680
        true_format._network_name = true_name
1969
1681
        self.assertEqual(True, true_format.fast_deltas)
1970
 
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
 
1682
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
1971
1683
        false_format = RemoteRepositoryFormat()
1972
1684
        false_format._network_name = false_name
1973
1685
        self.assertEqual(False, false_format.fast_deltas)
1974
1686
 
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
 
 
1982
1687
 
1983
1688
class TestRepositoryGatherStats(TestRemoteRepository):
1984
1689
 
2169
1874
        self.assertLength(1, self.hpss_calls)
2170
1875
 
2171
1876
    def disableExtraResults(self):
2172
 
        self.overrideAttr(SmartServerRepositoryGetParentMap,
2173
 
                          'no_extra_results', True)
 
1877
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
 
1878
        SmartServerRepositoryGetParentMap.no_extra_results = True
 
1879
        def reset_values():
 
1880
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
 
1881
        self.addCleanup(reset_values)
2174
1882
 
2175
1883
    def test_null_cached_missing_and_stop_key(self):
2176
1884
        self.setup_smart_server_with_call_log()
2235
1943
 
2236
1944
    def test_allows_new_revisions(self):
2237
1945
        """get_parent_map's results can be updated by commit."""
2238
 
        smart_server = test_server.SmartTCPServer_for_testing()
2239
 
        self.start_server(smart_server)
 
1946
        smart_server = server.SmartTCPServer_for_testing()
 
1947
        smart_server.setUp()
 
1948
        self.addCleanup(smart_server.tearDown)
2240
1949
        self.make_branch('branch')
2241
1950
        branch = Branch.open(smart_server.get_url() + '/branch')
2242
1951
        tree = branch.create_checkout('tree', lightweight=True)
2351
2060
        """
2352
2061
        # Make a repo with a fallback repo, both using a FakeClient.
2353
2062
        format = remote.response_tuple_to_repo_format(
2354
 
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
 
2063
            ('yes', 'no', 'yes', 'fake-network-name'))
2355
2064
        repo, client = self.setup_fake_client_and_repository('quack')
2356
2065
        repo._format = format
2357
2066
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2358
2067
            'fallback')
2359
2068
        fallback_repo._client = client
2360
 
        fallback_repo._format = format
2361
2069
        repo.add_fallback_repository(fallback_repo)
2362
2070
        # First the client should ask the primary repo
2363
2071
        client.add_expected_call(
2384
2092
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2385
2093
        self.assertFinished(client)
2386
2094
 
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
 
 
2408
2095
 
2409
2096
class TestRepositoryIsShared(TestRemoteRepository):
2410
2097
 
2437
2124
        transport_path = 'quack'
2438
2125
        repo, client = self.setup_fake_client_and_repository(transport_path)
2439
2126
        client.add_success_response('ok', 'a token')
2440
 
        token = repo.lock_write().repository_token
 
2127
        result = repo.lock_write()
2441
2128
        self.assertEqual(
2442
2129
            [('call', 'Repository.lock_write', ('quack/', ''))],
2443
2130
            client._calls)
2444
 
        self.assertEqual('a token', token)
 
2131
        self.assertEqual('a token', result)
2445
2132
 
2446
2133
    def test_lock_write_already_locked(self):
2447
2134
        transport_path = 'quack'
2526
2213
        self.assertEqual([], client._calls)
2527
2214
 
2528
2215
 
2529
 
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2530
 
    """Base class for Repository.insert_stream and .insert_stream_1.19
2531
 
    tests.
2532
 
    """
2533
 
    
2534
 
    def checkInsertEmptyStream(self, repo, client):
2535
 
        """Insert an empty stream, checking the result.
2536
 
 
2537
 
        This checks that there are no resume_tokens or missing_keys, and that
2538
 
        the client is finished.
2539
 
        """
2540
 
        sink = repo._get_sink()
2541
 
        fmt = repository.format_registry.get_default()
2542
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2543
 
        self.assertEqual([], resume_tokens)
2544
 
        self.assertEqual(set(), missing_keys)
2545
 
        self.assertFinished(client)
2546
 
 
2547
 
 
2548
 
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
2549
 
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
 
2216
class TestRepositoryInsertStream(TestRemoteRepository):
 
2217
    """Tests for using Repository.insert_stream verb when the _1.18 variant is
2550
2218
    not available.
2551
2219
 
2552
 
    This test case is very similar to TestRepositoryInsertStream_1_19.
 
2220
    This test case is very similar to TestRepositoryInsertStream_1_18.
2553
2221
    """
2554
2222
 
2555
2223
    def setUp(self):
2556
2224
        TestRemoteRepository.setUp(self)
2557
 
        self.disable_verb('Repository.insert_stream_1.19')
 
2225
        self.disable_verb('Repository.insert_stream_1.18')
2558
2226
 
2559
2227
    def test_unlocked_repo(self):
2560
2228
        transport_path = 'quack'
2561
2229
        repo, client = self.setup_fake_client_and_repository(transport_path)
2562
2230
        client.add_expected_call(
2563
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2564
 
            'unknown', ('Repository.insert_stream_1.19',))
2565
 
        client.add_expected_call(
2566
 
            'Repository.insert_stream', ('quack/', ''),
2567
 
            'success', ('ok',))
2568
 
        client.add_expected_call(
2569
 
            'Repository.insert_stream', ('quack/', ''),
2570
 
            'success', ('ok',))
2571
 
        self.checkInsertEmptyStream(repo, client)
 
2231
            'Repository.insert_stream_1.18', ('quack/', ''),
 
2232
            'unknown', ('Repository.insert_stream_1.18',))
 
2233
        client.add_expected_call(
 
2234
            'Repository.insert_stream', ('quack/', ''),
 
2235
            'success', ('ok',))
 
2236
        client.add_expected_call(
 
2237
            'Repository.insert_stream', ('quack/', ''),
 
2238
            'success', ('ok',))
 
2239
        sink = repo._get_sink()
 
2240
        fmt = repository.RepositoryFormat.get_default_format()
 
2241
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2242
        self.assertEqual([], resume_tokens)
 
2243
        self.assertEqual(set(), missing_keys)
 
2244
        self.assertFinished(client)
2572
2245
 
2573
2246
    def test_locked_repo_with_no_lock_token(self):
2574
2247
        transport_path = 'quack'
2577
2250
            'Repository.lock_write', ('quack/', ''),
2578
2251
            'success', ('ok', ''))
2579
2252
        client.add_expected_call(
2580
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2581
 
            'unknown', ('Repository.insert_stream_1.19',))
 
2253
            'Repository.insert_stream_1.18', ('quack/', ''),
 
2254
            'unknown', ('Repository.insert_stream_1.18',))
2582
2255
        client.add_expected_call(
2583
2256
            'Repository.insert_stream', ('quack/', ''),
2584
2257
            'success', ('ok',))
2586
2259
            'Repository.insert_stream', ('quack/', ''),
2587
2260
            'success', ('ok',))
2588
2261
        repo.lock_write()
2589
 
        self.checkInsertEmptyStream(repo, client)
 
2262
        sink = repo._get_sink()
 
2263
        fmt = repository.RepositoryFormat.get_default_format()
 
2264
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2265
        self.assertEqual([], resume_tokens)
 
2266
        self.assertEqual(set(), missing_keys)
 
2267
        self.assertFinished(client)
2590
2268
 
2591
2269
    def test_locked_repo_with_lock_token(self):
2592
2270
        transport_path = 'quack'
2595
2273
            'Repository.lock_write', ('quack/', ''),
2596
2274
            'success', ('ok', 'a token'))
2597
2275
        client.add_expected_call(
2598
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2599
 
            'unknown', ('Repository.insert_stream_1.19',))
 
2276
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
 
2277
            'unknown', ('Repository.insert_stream_1.18',))
2600
2278
        client.add_expected_call(
2601
2279
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2602
2280
            'success', ('ok',))
2604
2282
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2605
2283
            'success', ('ok',))
2606
2284
        repo.lock_write()
2607
 
        self.checkInsertEmptyStream(repo, client)
 
2285
        sink = repo._get_sink()
 
2286
        fmt = repository.RepositoryFormat.get_default_format()
 
2287
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2288
        self.assertEqual([], resume_tokens)
 
2289
        self.assertEqual(set(), missing_keys)
 
2290
        self.assertFinished(client)
2608
2291
 
2609
2292
    def test_stream_with_inventory_deltas(self):
2610
 
        """'inventory-deltas' substreams cannot be sent to the
2611
 
        Repository.insert_stream verb, because not all servers that implement
2612
 
        that verb will accept them.  So when one is encountered the RemoteSink
2613
 
        immediately stops using that verb and falls back to VFS insert_stream.
 
2293
        """'inventory-deltas' substreams can't be sent to the
 
2294
        Repository.insert_stream verb.  So when one is encountered the
 
2295
        RemoteSink immediately stops using that verb and falls back to VFS
 
2296
        insert_stream.
2614
2297
        """
2615
2298
        transport_path = 'quack'
2616
2299
        repo, client = self.setup_fake_client_and_repository(transport_path)
2617
2300
        client.add_expected_call(
2618
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2619
 
            'unknown', ('Repository.insert_stream_1.19',))
 
2301
            'Repository.insert_stream_1.18', ('quack/', ''),
 
2302
            'unknown', ('Repository.insert_stream_1.18',))
2620
2303
        client.add_expected_call(
2621
2304
            'Repository.insert_stream', ('quack/', ''),
2622
2305
            'success', ('ok',))
2638
2321
        class FakeRealRepository:
2639
2322
            def _get_sink(self):
2640
2323
                return fake_real_sink
2641
 
            def is_in_write_group(self):
2642
 
                return False
2643
 
            def refresh_data(self):
2644
 
                return True
2645
2324
        repo._real_repository = FakeRealRepository()
2646
2325
        sink = repo._get_sink()
2647
 
        fmt = repository.format_registry.get_default()
 
2326
        fmt = repository.RepositoryFormat.get_default_format()
2648
2327
        stream = self.make_stream_with_inv_deltas(fmt)
2649
2328
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2650
2329
        # Every record from the first inventory delta should have been sent to
2671
2350
        """
2672
2351
        # Define a stream using generators so that it isn't rewindable.
2673
2352
        inv = inventory.Inventory(revision_id='rev1')
2674
 
        inv.root.revision = 'rev1'
2675
2353
        def stream_with_inv_delta():
2676
2354
            yield ('inventories', inventories_substream())
2677
2355
            yield ('inventory-deltas', inventory_delta_substream())
2690
2368
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
2691
2369
            entry.revision = 'ghost'
2692
2370
            delta = [(None, 'newdir', 'newdir-id', entry)]
2693
 
            serializer = inventory_delta.InventoryDeltaSerializer(
2694
 
                versioned_root=True, tree_references=False)
 
2371
            serializer = inventory_delta.InventoryDeltaSerializer()
 
2372
            serializer.require_flags(True, False)
2695
2373
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
2696
2374
            yield versionedfile.ChunkedContentFactory(
2697
2375
                ('rev2',), (('rev1',)), None, lines)
2702
2380
        return stream_with_inv_delta()
2703
2381
 
2704
2382
 
2705
 
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
 
2383
class TestRepositoryInsertStream_1_18(TestRemoteRepository):
2706
2384
 
2707
2385
    def test_unlocked_repo(self):
2708
2386
        transport_path = 'quack'
2709
2387
        repo, client = self.setup_fake_client_and_repository(transport_path)
2710
2388
        client.add_expected_call(
2711
 
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2389
            'Repository.insert_stream_1.18', ('quack/', ''),
2712
2390
            'success', ('ok',))
2713
2391
        client.add_expected_call(
2714
 
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2392
            'Repository.insert_stream_1.18', ('quack/', ''),
2715
2393
            'success', ('ok',))
2716
 
        self.checkInsertEmptyStream(repo, client)
 
2394
        sink = repo._get_sink()
 
2395
        fmt = repository.RepositoryFormat.get_default_format()
 
2396
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2397
        self.assertEqual([], resume_tokens)
 
2398
        self.assertEqual(set(), missing_keys)
 
2399
        self.assertFinished(client)
2717
2400
 
2718
2401
    def test_locked_repo_with_no_lock_token(self):
2719
2402
        transport_path = 'quack'
2722
2405
            'Repository.lock_write', ('quack/', ''),
2723
2406
            'success', ('ok', ''))
2724
2407
        client.add_expected_call(
2725
 
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2408
            'Repository.insert_stream_1.18', ('quack/', ''),
2726
2409
            'success', ('ok',))
2727
2410
        client.add_expected_call(
2728
 
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2411
            'Repository.insert_stream_1.18', ('quack/', ''),
2729
2412
            'success', ('ok',))
2730
2413
        repo.lock_write()
2731
 
        self.checkInsertEmptyStream(repo, client)
 
2414
        sink = repo._get_sink()
 
2415
        fmt = repository.RepositoryFormat.get_default_format()
 
2416
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2417
        self.assertEqual([], resume_tokens)
 
2418
        self.assertEqual(set(), missing_keys)
 
2419
        self.assertFinished(client)
2732
2420
 
2733
2421
    def test_locked_repo_with_lock_token(self):
2734
2422
        transport_path = 'quack'
2737
2425
            'Repository.lock_write', ('quack/', ''),
2738
2426
            'success', ('ok', 'a token'))
2739
2427
        client.add_expected_call(
2740
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2428
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
2741
2429
            'success', ('ok',))
2742
2430
        client.add_expected_call(
2743
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2431
            'Repository.insert_stream_1.18', ('quack/', '', 'a token'),
2744
2432
            'success', ('ok',))
2745
2433
        repo.lock_write()
2746
 
        self.checkInsertEmptyStream(repo, client)
 
2434
        sink = repo._get_sink()
 
2435
        fmt = repository.RepositoryFormat.get_default_format()
 
2436
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2437
        self.assertEqual([], resume_tokens)
 
2438
        self.assertEqual(set(), missing_keys)
 
2439
        self.assertFinished(client)
2747
2440
 
2748
2441
 
2749
2442
class TestRepositoryTarball(TestRemoteRepository):
2785
2478
    """RemoteRepository.copy_content_into optimizations"""
2786
2479
 
2787
2480
    def test_copy_content_remote_to_local(self):
2788
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2481
        self.transport_server = server.SmartTCPServer_for_testing
2789
2482
        src_repo = self.make_repository('repo1')
2790
2483
        src_repo = repository.Repository.open(self.get_url('repo1'))
2791
2484
        # At the moment the tarball-based copy_content_into can't write back
2870
2563
             ('pack collection autopack',)],
2871
2564
            client._calls)
2872
2565
 
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
 
 
2883
2566
 
2884
2567
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2885
2568
    """Base class for unit tests for bzrlib.remote._translate_error."""
2949
2632
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2950
2633
        self.assertEqual(expected_error, translated_error)
2951
2634
 
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
 
 
2968
2635
    def test_LockContention(self):
2969
2636
        translated_error = self.translateTuple(('LockContention',))
2970
2637
        expected_error = errors.LockContention('(remote lock)')
2998
2665
        expected_error = errors.DivergedBranches(branch, other_branch)
2999
2666
        self.assertEqual(expected_error, translated_error)
3000
2667
 
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
 
 
3007
2668
    def test_ReadError_no_args(self):
3008
2669
        path = 'a path'
3009
2670
        translated_error = self.translateTuple(('ReadError',), path=path)
3016
2677
        expected_error = errors.ReadError(path)
3017
2678
        self.assertEqual(expected_error, translated_error)
3018
2679
 
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
 
 
3026
2680
    def test_PermissionDenied_no_args(self):
3027
2681
        path = 'a path'
3028
 
        translated_error = self.translateTuple(('PermissionDenied',),
3029
 
            path=path)
 
2682
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
3030
2683
        expected_error = errors.PermissionDenied(path)
3031
2684
        self.assertEqual(expected_error, translated_error)
3032
2685
 
3055
2708
        expected_error = errors.PermissionDenied(path, extra)
3056
2709
        self.assertEqual(expected_error, translated_error)
3057
2710
 
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
 
 
3097
2711
 
3098
2712
class TestErrorTranslationRobustness(TestErrorTranslationBase):
3099
2713
    """Unit tests for bzrlib.remote._translate_error's robustness.
3129
2743
        # In addition to re-raising ErrorFromSmartServer, some debug info has
3130
2744
        # been muttered to the log file for developer to look at.
3131
2745
        self.assertContainsRe(
3132
 
            self.get_log(),
 
2746
            self._get_log(keep_log_file=True),
3133
2747
            "Missing key 'branch' in context")
3134
2748
 
3135
2749
    def test_path_missing(self):
3143
2757
        self.assertEqual(server_error, translated_error)
3144
2758
        # In addition to re-raising ErrorFromSmartServer, some debug info has
3145
2759
        # been muttered to the log file for developer to look at.
3146
 
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
 
2760
        self.assertContainsRe(
 
2761
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
3147
2762
 
3148
2763
 
3149
2764
class TestStacking(tests.TestCaseWithTransport):
3167
2782
        stacked_branch = self.make_branch('stacked', format='1.9')
3168
2783
        stacked_branch.set_stacked_on_url('../base')
3169
2784
        # start a server looking at this
3170
 
        smart_server = test_server.SmartTCPServer_for_testing()
3171
 
        self.start_server(smart_server)
 
2785
        smart_server = server.SmartTCPServer_for_testing()
 
2786
        smart_server.setUp()
 
2787
        self.addCleanup(smart_server.tearDown)
3172
2788
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
3173
2789
        # can get its branch and repository
3174
2790
        remote_branch = remote_bzrdir.open_branch()
3196
2812
        tree1.commit('rev1', rev_id='rev1')
3197
2813
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
3198
2814
            ).open_workingtree()
3199
 
        local_tree = tree2.branch.create_checkout('local')
3200
 
        local_tree.commit('local changes make me feel good.')
 
2815
        tree2.commit('local changes make me feel good.')
3201
2816
        branch2 = Branch.open(self.get_url('tree2'))
3202
2817
        branch2.lock_read()
3203
2818
        self.addCleanup(branch2.unlock)
3244
2859
        _, stacked = branch_factory()
3245
2860
        source = stacked.repository._get_source(target_repository_format)
3246
2861
        tip = stacked.last_revision()
3247
 
        stacked.repository._ensure_real()
3248
 
        graph = stacked.repository.get_graph()
3249
 
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
3250
 
                if r != NULL_REVISION]
3251
 
        revs.reverse()
3252
 
        search = _mod_graph.PendingAncestryResult([tip], stacked.repository)
 
2862
        revs = stacked.repository.get_ancestry(tip)
 
2863
        search = graph.PendingAncestryResult([tip], stacked.repository)
3253
2864
        self.reset_smart_call_log()
3254
2865
        stream = source.get_stream(search)
 
2866
        if None in revs:
 
2867
            revs.remove(None)
3255
2868
        # We trust that if a revision is in the stream the rest of the new
3256
2869
        # content for it is too, as per our main fetch tests; here we are
3257
2870
        # checking that the revisions are actually included at all, and their
3275
2888
            _, stacked = self.prepare_stacked_remote_branch()
3276
2889
            tree = stacked.bzrdir.sprout('tree3', stacked=True
3277
2890
                ).open_workingtree()
3278
 
            local_tree = tree.branch.create_checkout('local-tree3')
3279
 
            local_tree.commit('more local changes are better')
 
2891
            tree.commit('more local changes are better')
3280
2892
            branch = Branch.open(self.get_url('tree3'))
3281
2893
            branch.lock_read()
3282
 
            self.addCleanup(branch.unlock)
3283
2894
            return None, branch
3284
2895
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
3285
2896
            branch_factory=make_stacked_stacked)
3294
2905
        # stacked upon sources in topological order.
3295
2906
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
3296
2907
        self.assertEqual(expected_revs, rev_ord)
3297
 
        # Getting topological sort requires VFS calls still - one of which is
3298
 
        # pushing up from the bound branch.
3299
 
        self.assertLength(14, self.hpss_calls)
 
2908
        # Getting topological sort requires VFS calls still
 
2909
        self.assertLength(12, self.hpss_calls)
3300
2910
 
3301
2911
    def test_stacked_get_stream_groupcompress(self):
3302
2912
        # Repository._get_source.get_stream() from a stacked repository with
3331
2941
        super(TestRemoteBranchEffort, self).setUp()
3332
2942
        # Create a smart server that publishes whatever the backing VFS server
3333
2943
        # does.
3334
 
        self.smart_server = test_server.SmartTCPServer_for_testing()
3335
 
        self.start_server(self.smart_server, self.get_server())
 
2944
        self.smart_server = server.SmartTCPServer_for_testing()
 
2945
        self.smart_server.setUp(self.get_server())
 
2946
        self.addCleanup(self.smart_server.tearDown)
3336
2947
        # Log all HPSS calls into self.hpss_calls.
3337
2948
        _SmartClient.hooks.install_named_hook(
3338
2949
            'call', self.capture_hpss_call, None)
3343
2954
 
3344
2955
    def test_copy_content_into_avoids_revision_history(self):
3345
2956
        local = self.make_branch('local')
3346
 
        builder = self.make_branch_builder('remote')
3347
 
        builder.build_commit(message="Commit.")
 
2957
        remote_backing_tree = self.make_branch_and_tree('remote')
 
2958
        remote_backing_tree.commit("Commit.")
3348
2959
        remote_branch_url = self.smart_server.get_url() + 'remote'
3349
2960
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3350
2961
        local.repository.fetch(remote_branch.repository)
3351
2962
        self.hpss_calls = []
3352
2963
        remote_branch.copy_content_into(local)
3353
2964
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
3354
 
 
3355
 
    def test_fetch_everything_needs_just_one_call(self):
3356
 
        local = self.make_branch('local')
3357
 
        builder = self.make_branch_builder('remote')
3358
 
        builder.build_commit(message="Commit.")
3359
 
        remote_branch_url = self.smart_server.get_url() + 'remote'
3360
 
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3361
 
        self.hpss_calls = []
3362
 
        local.repository.fetch(remote_branch.repository,
3363
 
                fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3364
 
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
3365
 
 
3366
 
    def override_verb(self, verb_name, verb):
3367
 
        request_handlers = request.request_handlers
3368
 
        orig_verb = request_handlers.get(verb_name)
3369
 
        request_handlers.register(verb_name, verb, override_existing=True)
3370
 
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
3371
 
                override_existing=True)
3372
 
 
3373
 
    def test_fetch_everything_backwards_compat(self):
3374
 
        """Can fetch with EverythingResult even with pre 2.4 servers.
3375
 
        
3376
 
        Pre-2.4 do not support 'everything' searches with the
3377
 
        Repository.get_stream_1.19 verb.
3378
 
        """
3379
 
        verb_log = []
3380
 
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
3381
 
            """A version of the Repository.get_stream_1.19 verb patched to
3382
 
            reject 'everything' searches the way 2.3 and earlier do.
3383
 
            """
3384
 
            def recreate_search(self, repository, search_bytes, discard_excess=False):
3385
 
                verb_log.append(search_bytes.split('\n', 1)[0])
3386
 
                if search_bytes == 'everything':
3387
 
                    return (None, request.FailedSmartServerResponse(('BadSearch',)))
3388
 
                return super(OldGetStreamVerb,
3389
 
                        self).recreate_search(repository, search_bytes,
3390
 
                            discard_excess=discard_excess)
3391
 
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
3392
 
        local = self.make_branch('local')
3393
 
        builder = self.make_branch_builder('remote')
3394
 
        builder.build_commit(message="Commit.")
3395
 
        remote_branch_url = self.smart_server.get_url() + 'remote'
3396
 
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3397
 
        self.hpss_calls = []
3398
 
        local.repository.fetch(remote_branch.repository,
3399
 
                fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3400
 
        # make sure the overridden verb was used
3401
 
        self.assertLength(1, verb_log)
3402
 
        # more than one HPSS call is needed, but because it's a VFS callback
3403
 
        # its hard to predict exactly how many.
3404
 
        self.assertTrue(len(self.hpss_calls) > 1)
3405