113
114
self.assertStartsWith(str(b), 'RemoteBranch(')
116
class FakeRemoteTransport(object):
117
"""This class provides the minimum support for use in place of a RemoteTransport.
119
It doesn't actually transmit requests, but rather expects them to be
120
handled by a FakeClient which holds canned responses. It does not allow
121
any vfs access, therefore is not suitable for testing any operation that
122
will fallback to vfs access. Backing the test by an instance of this
123
class guarantees that it's - done using non-vfs operations.
126
_default_url = 'fakeremotetransport://host/path/'
128
def __init__(self, url=None):
130
url = self._default_url
134
return "%r(%r)" % (self.__class__.__name__,
137
def clone(self, relpath):
138
return FakeRemoteTransport(urlutils.join(self.base, relpath))
140
def get(self, relpath):
141
# only get is specifically stubbed out, because it's usually the first
142
# thing we do. anything else will fail with an AttributeError.
143
raise AssertionError("%r doesn't support file access to %r"
148
117
class FakeProtocol(object):
149
118
"""Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
253
227
self.expecting_body = True
254
228
return result[1], FakeProtocol(result[2], self)
230
def call_with_body_stream(self, args, stream):
231
# Explicitly consume the stream before checking for an error, because
232
# that's what happens a real medium.
233
stream = list(stream)
234
self._check_call(args[0], args[1:])
235
self._calls.append(('call_with_body_stream', args[0], args[1:], stream))
236
return self._get_next_response()[1]
257
239
class FakeMedium(medium.SmartClientMedium):
367
361
client.add_expected_call(
368
362
'Branch.get_stacked_on_url', ('quack/',),
369
363
'error', ('NotStacked',))
370
bzrdir = RemoteBzrDir(transport, _client=client)
364
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
371
366
result = bzrdir.open_branch()
372
367
self.assertIsInstance(result, RemoteBranch)
373
368
self.assertEqual(bzrdir, result.bzrdir)
460
459
RemoteBzrDirFormat.probe_transport, OldServerTransport())
462
class TestBzrDirCreateBranch(TestRemote):
464
def test_backwards_compat(self):
465
self.setup_smart_server_with_call_log()
466
repo = self.make_repository('.')
467
self.reset_smart_call_log()
468
self.disable_verb('BzrDir.create_branch')
469
branch = repo.bzrdir.create_branch()
470
create_branch_call_count = len([call for call in self.hpss_calls if
471
call[0].method == 'BzrDir.create_branch'])
472
self.assertEqual(1, create_branch_call_count)
474
def test_current_server(self):
475
transport = self.get_transport('.')
476
transport = transport.clone('quack')
477
self.make_repository('quack')
478
client = FakeClient(transport.base)
479
reference_bzrdir_format = bzrdir.format_registry.get('default')()
480
reference_format = reference_bzrdir_format.get_branch_format()
481
network_name = reference_format.network_name()
482
reference_repo_fmt = reference_bzrdir_format.repository_format
483
reference_repo_name = reference_repo_fmt.network_name()
484
client.add_expected_call(
485
'BzrDir.create_branch', ('quack/', network_name),
486
'success', ('ok', network_name, '', 'no', 'no', 'yes',
487
reference_repo_name))
488
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
490
branch = a_bzrdir.create_branch()
491
# We should have got a remote branch
492
self.assertIsInstance(branch, remote.RemoteBranch)
493
# its format should have the settings from the response
494
format = branch._format
495
self.assertEqual(network_name, format.network_name())
498
class TestBzrDirCreateRepository(TestRemote):
500
def test_backwards_compat(self):
501
self.setup_smart_server_with_call_log()
502
bzrdir = self.make_bzrdir('.')
503
self.reset_smart_call_log()
504
self.disable_verb('BzrDir.create_repository')
505
repo = bzrdir.create_repository()
506
create_repo_call_count = len([call for call in self.hpss_calls if
507
call[0].method == 'BzrDir.create_repository'])
508
self.assertEqual(1, create_repo_call_count)
510
def test_current_server(self):
511
transport = self.get_transport('.')
512
transport = transport.clone('quack')
513
self.make_bzrdir('quack')
514
client = FakeClient(transport.base)
515
reference_bzrdir_format = bzrdir.format_registry.get('default')()
516
reference_format = reference_bzrdir_format.repository_format
517
network_name = reference_format.network_name()
518
client.add_expected_call(
519
'BzrDir.create_repository', ('quack/',
520
'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
521
'success', ('ok', 'no', 'no', 'no', network_name))
522
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
524
repo = a_bzrdir.create_repository()
525
# We should have got a remote repository
526
self.assertIsInstance(repo, remote.RemoteRepository)
527
# its format should have the settings from the response
528
format = repo._format
529
self.assertFalse(format.rich_root_data)
530
self.assertFalse(format.supports_tree_reference)
531
self.assertFalse(format.supports_external_lookups)
532
self.assertEqual(network_name, format.network_name())
463
535
class TestBzrDirOpenRepository(tests.TestCase):
465
537
def test_backwards_compat_1_2(self):
467
539
transport.mkdir('quack')
468
540
transport = transport.clone('quack')
469
541
client = FakeClient(transport.base)
470
client.add_unknown_method_response('RemoteRepository.find_repositoryV2')
542
client.add_unknown_method_response('BzrDir.find_repositoryV2')
471
543
client.add_success_response('ok', '', 'no', 'no')
472
bzrdir = RemoteBzrDir(transport, _client=client)
544
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
473
546
repo = bzrdir.open_repository()
474
547
self.assertEqual(
475
548
[('call', 'BzrDir.find_repositoryV2', ('quack/',)),
510
583
def make_remote_branch(self, transport, client):
511
584
"""Make a RemoteBranch using 'client' as its _SmartClient.
513
586
A RemoteBzrDir and RemoteRepository will also be created to fill out
514
587
the RemoteBranch, albeit with stub values for some of their attributes.
516
589
# we do not want bzrdir to make any remote calls, so use False as its
517
590
# _client. If it tries to make a remote call, this will fail
519
bzrdir = RemoteBzrDir(transport, _client=False)
592
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
520
594
repo = RemoteRepository(bzrdir, None, _client=client)
521
595
return RemoteBranch(bzrdir, repo, _client=client)
562
636
"""Test Branch._get_stacked_on_url rpc"""
564
638
def test_get_stacked_on_invalid_url(self):
565
raise tests.KnownFailure('opening a branch requires the server to open the fallback repository')
566
transport = FakeRemoteTransport('fakeremotetransport:///')
639
# test that asking for a stacked on url the server can't access works.
640
# This isn't perfect, but then as we're in the same process there
641
# really isn't anything we can do to be 100% sure that the server
642
# doesn't just open in - this test probably needs to be rewritten using
643
# a spawn()ed server.
644
stacked_branch = self.make_branch('stacked', format='1.9')
645
memory_branch = self.make_branch('base', format='1.9')
646
vfs_url = self.get_vfs_only_url('base')
647
stacked_branch.set_stacked_on_url(vfs_url)
648
transport = stacked_branch.bzrdir.root_transport
567
649
client = FakeClient(transport.base)
568
650
client.add_expected_call(
569
'Branch.get_stacked_on_url', ('.',),
570
'success', ('ok', 'file:///stacked/on'))
571
bzrdir = RemoteBzrDir(transport, _client=client)
572
branch = RemoteBranch(bzrdir, None, _client=client)
651
'Branch.get_stacked_on_url', ('stacked/',),
652
'success', ('ok', vfs_url))
653
# XXX: Multiple calls are bad, this second call documents what is
655
client.add_expected_call(
656
'Branch.get_stacked_on_url', ('stacked/',),
657
'success', ('ok', vfs_url))
658
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
660
branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, None),
573
662
result = branch.get_stacked_on_url()
575
'file:///stacked/on', result)
663
self.assertEqual(vfs_url, result)
577
665
def test_backwards_compatible(self):
578
666
# like with bzr1.6 with no Branch.get_stacked_on_url rpc
595
683
'unknown', ('Branch.get_stacked_on_url',))
596
684
# this will also do vfs access, but that goes direct to the transport
597
685
# and isn't seen by the FakeClient.
598
bzrdir = RemoteBzrDir(self.get_transport('stacked'), _client=client)
686
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
687
remote.RemoteBzrDirFormat(), _client=client)
599
688
branch = bzrdir.open_branch()
600
689
result = branch.get_stacked_on_url()
601
690
self.assertEqual('../base', result)
624
713
client.add_expected_call(
625
714
'Branch.get_stacked_on_url', ('stacked/',),
626
715
'success', ('ok', '../base'))
627
bzrdir = RemoteBzrDir(self.get_transport('stacked'), _client=client)
716
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
717
remote.RemoteBzrDirFormat(), _client=client)
628
718
branch = bzrdir.open_branch()
629
719
result = branch.get_stacked_on_url()
630
720
self.assertEqual('../base', result)
653
743
'Branch.lock_write', ('branch/', '', ''),
654
744
'success', ('ok', 'branch token', 'repo token'))
655
745
client.add_expected_call(
746
'Branch.last_revision_info',
748
'success', ('ok', '0', 'null:'))
749
client.add_expected_call(
656
750
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
657
751
'success', ('ok',))
658
752
client.add_expected_call(
683
777
'Branch.lock_write', ('branch/', '', ''),
684
778
'success', ('ok', 'branch token', 'repo token'))
685
779
client.add_expected_call(
780
'Branch.last_revision_info',
782
'success', ('ok', '0', 'null:'))
784
encoded_body = bz2.compress('\n'.join(lines))
785
client.add_success_response_with_body(encoded_body, 'ok')
786
client.add_expected_call(
686
787
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
687
788
'success', ('ok',))
688
789
client.add_expected_call(
712
813
'Branch.lock_write', ('branch/', '', ''),
713
814
'success', ('ok', 'branch token', 'repo token'))
714
815
client.add_expected_call(
816
'Branch.last_revision_info',
818
'success', ('ok', '0', 'null:'))
819
# get_graph calls to construct the revision history, for the set_rh
822
encoded_body = bz2.compress('\n'.join(lines))
823
client.add_success_response_with_body(encoded_body, 'ok')
824
client.add_expected_call(
715
825
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
716
826
'error', ('NoSuchRevision', 'rev-id'))
717
827
client.add_expected_call(
742
852
'Branch.lock_write', ('branch/', '', ''),
743
853
'success', ('ok', 'branch token', 'repo token'))
744
854
client.add_expected_call(
855
'Branch.last_revision_info',
857
'success', ('ok', '0', 'null:'))
859
encoded_body = bz2.compress('\n'.join(lines))
860
client.add_success_response_with_body(encoded_body, 'ok')
861
client.add_expected_call(
745
862
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
746
863
'error', ('TipChangeRejected', rejection_msg_utf8))
747
864
client.add_expected_call(
847
966
'Branch.get_stacked_on_url', ('branch/',),
848
967
'error', ('NotStacked',))
849
968
client.add_expected_call(
969
'Branch.last_revision_info',
971
'success', ('ok', '0', 'null:'))
972
client.add_expected_call(
850
973
'Branch.set_last_revision_info',
851
974
('branch/', 'branch token', 'repo token', '1234', 'a-revision-id',),
852
975
'unknown', 'Branch.set_last_revision_info')
1042
1165
self.assertEqual('bar', t._get_credentials()[0])
1045
class TestRemoteRepository(tests.TestCase):
1168
class TestRemoteRepository(TestRemote):
1046
1169
"""Base for testing RemoteRepository protocol usage.
1048
These tests contain frozen requests and responses. We want any changes to
1171
These tests contain frozen requests and responses. We want any changes to
1049
1172
what is sent or expected to be require a thoughtful update to these tests
1050
1173
because they might break compatibility with different-versioned servers.
1053
1176
def setup_fake_client_and_repository(self, transport_path):
1054
1177
"""Create the fake client and repository for testing with.
1056
1179
There's no real server here; we just have canned responses sent
1057
1180
back one by one.
1059
1182
:param transport_path: Path below the root of the MemoryTransport
1060
1183
where the repository will be created.
1511
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
1513
def test_backwards_compat(self):
1514
self.setup_smart_server_with_call_log()
1515
repo = self.make_repository('.')
1516
self.reset_smart_call_log()
1517
verb = 'Repository.set_make_working_trees'
1518
self.disable_verb(verb)
1519
repo.set_make_working_trees(True)
1520
call_count = len([call for call in self.hpss_calls if
1521
call[0].method == verb])
1522
self.assertEqual(1, call_count)
1524
def test_current(self):
1525
transport_path = 'quack'
1526
repo, client = self.setup_fake_client_and_repository(transport_path)
1527
client.add_expected_call(
1528
'Repository.set_make_working_trees', ('quack/', 'True'),
1530
client.add_expected_call(
1531
'Repository.set_make_working_trees', ('quack/', 'False'),
1533
repo.set_make_working_trees(True)
1534
repo.set_make_working_trees(False)
1387
1537
class TestRepositoryUnlock(TestRemoteRepository):
1389
1539
def test_unlock(self):