207
158
def add_unknown_method_response(self, verb):
208
159
self.responses.append(('unknown', verb))
210
def finished_test(self):
211
if self._expected_calls:
212
raise AssertionError("%r finished but was still expecting %r"
213
% (self, self._expected_calls[0]))
215
161
def _get_next_response(self):
217
response_tuple = self.responses.pop(0)
218
except IndexError, e:
219
raise AssertionError("%r didn't expect any more calls"
162
response_tuple = self.responses.pop(0)
221
163
if response_tuple[0] == 'unknown':
222
164
raise errors.UnknownSmartMethod(response_tuple[1])
223
165
elif response_tuple[0] == 'error':
224
166
raise errors.ErrorFromSmartServer(response_tuple[1])
225
167
return response_tuple
227
def _check_call(self, method, args):
228
if self._expected_calls is None:
229
# the test should be updated to say what it expects
232
next_call = self._expected_calls.pop(0)
234
raise AssertionError("%r didn't expect any more calls "
236
% (self, method, args,))
237
if method != next_call[0] or args != next_call[1]:
238
raise AssertionError("%r expected %r%r "
240
% (self, next_call[0], next_call[1], method, args,))
242
169
def call(self, method, *args):
243
self._check_call(method, args)
244
170
self._calls.append(('call', method, args))
245
171
return self._get_next_response()[1]
247
173
def call_expecting_body(self, method, *args):
248
self._check_call(method, args)
249
174
self._calls.append(('call_expecting_body', method, args))
250
175
result = self._get_next_response()
251
176
self.expecting_body = True
252
177
return result[1], FakeProtocol(result[2], self)
254
179
def call_with_body_bytes_expecting_body(self, method, args, body):
255
self._check_call(method, args)
256
180
self._calls.append(('call_with_body_bytes_expecting_body', method,
258
182
result = self._get_next_response()
511
400
return OldSmartClient()
514
class RemoteBranchTestCase(tests.TestCase):
516
def make_remote_branch(self, transport, client):
517
"""Make a RemoteBranch using 'client' as its _SmartClient.
519
A RemoteBzrDir and RemoteRepository will also be created to fill out
520
the RemoteBranch, albeit with stub values for some of their attributes.
522
# we do not want bzrdir to make any remote calls, so use False as its
523
# _client. If it tries to make a remote call, this will fail
525
bzrdir = RemoteBzrDir(transport, _client=False)
526
repo = RemoteRepository(bzrdir, None, _client=client)
527
return RemoteBranch(bzrdir, repo, _client=client)
530
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
403
class TestBranchLastRevisionInfo(tests.TestCase):
532
405
def test_empty_branch(self):
533
406
# in an empty branch we decode the response properly
534
407
transport = MemoryTransport()
535
408
client = FakeClient(transport.base)
536
client.add_expected_call(
537
'Branch.get_stacked_on_url', ('quack/',),
538
'error', ('NotStacked',))
539
client.add_expected_call(
540
'Branch.last_revision_info', ('quack/',),
541
'success', ('ok', '0', 'null:'))
409
client.add_success_response('ok', '0', 'null:')
542
410
transport.mkdir('quack')
543
411
transport = transport.clone('quack')
544
branch = self.make_remote_branch(transport, client)
412
# we do not want bzrdir to make any remote calls
413
bzrdir = RemoteBzrDir(transport, _client=False)
414
branch = RemoteBranch(bzrdir, None, _client=client)
545
415
result = branch.last_revision_info()
546
client.finished_test()
418
[('call', 'Branch.last_revision_info', ('quack/',))],
547
420
self.assertEqual((0, NULL_REVISION), result)
549
422
def test_non_empty_branch(self):
551
424
revid = u'\xc8'.encode('utf8')
552
425
transport = MemoryTransport()
553
426
client = FakeClient(transport.base)
554
client.add_expected_call(
555
'Branch.get_stacked_on_url', ('kwaak/',),
556
'error', ('NotStacked',))
557
client.add_expected_call(
558
'Branch.last_revision_info', ('kwaak/',),
559
'success', ('ok', '2', revid))
427
client.add_success_response('ok', '2', revid)
560
428
transport.mkdir('kwaak')
561
429
transport = transport.clone('kwaak')
562
branch = self.make_remote_branch(transport, client)
430
# we do not want bzrdir to make any remote calls
431
bzrdir = RemoteBzrDir(transport, _client=False)
432
branch = RemoteBranch(bzrdir, None, _client=client)
563
433
result = branch.last_revision_info()
436
[('call', 'Branch.last_revision_info', ('kwaak/',))],
564
438
self.assertEqual((2, revid), result)
567
class TestBranch_get_stacked_on_url(tests.TestCaseWithMemoryTransport):
568
"""Test Branch._get_stacked_on_url rpc"""
570
def test_get_stacked_on_invalid_url(self):
571
raise tests.KnownFailure('opening a branch requires the server to open the fallback repository')
572
transport = FakeRemoteTransport('fakeremotetransport:///')
573
client = FakeClient(transport.base)
574
client.add_expected_call(
575
'Branch.get_stacked_on_url', ('.',),
576
'success', ('ok', 'file:///stacked/on'))
577
bzrdir = RemoteBzrDir(transport, _client=client)
578
branch = RemoteBranch(bzrdir, None, _client=client)
579
result = branch.get_stacked_on_url()
581
'file:///stacked/on', result)
583
def test_backwards_compatible(self):
584
# like with bzr1.6 with no Branch.get_stacked_on_url rpc
585
base_branch = self.make_branch('base', format='1.6')
586
stacked_branch = self.make_branch('stacked', format='1.6')
587
stacked_branch.set_stacked_on_url('../base')
588
client = FakeClient(self.get_url())
589
client.add_expected_call(
590
'BzrDir.open_branch', ('stacked/',),
591
'success', ('ok', ''))
592
client.add_expected_call(
593
'BzrDir.find_repositoryV2', ('stacked/',),
594
'success', ('ok', '', 'no', 'no', 'no'))
595
# called twice, once from constructor and then again by us
596
client.add_expected_call(
597
'Branch.get_stacked_on_url', ('stacked/',),
598
'unknown', ('Branch.get_stacked_on_url',))
599
client.add_expected_call(
600
'Branch.get_stacked_on_url', ('stacked/',),
601
'unknown', ('Branch.get_stacked_on_url',))
602
# this will also do vfs access, but that goes direct to the transport
603
# and isn't seen by the FakeClient.
604
bzrdir = RemoteBzrDir(self.get_transport('stacked'), _client=client)
605
branch = bzrdir.open_branch()
606
result = branch.get_stacked_on_url()
607
self.assertEqual('../base', result)
608
client.finished_test()
609
# it's in the fallback list both for the RemoteRepository and its vfs
611
self.assertEqual(1, len(branch.repository._fallback_repositories))
613
len(branch.repository._real_repository._fallback_repositories))
615
def test_get_stacked_on_real_branch(self):
616
base_branch = self.make_branch('base', format='1.6')
617
stacked_branch = self.make_branch('stacked', format='1.6')
618
stacked_branch.set_stacked_on_url('../base')
619
client = FakeClient(self.get_url())
620
client.add_expected_call(
621
'BzrDir.open_branch', ('stacked/',),
622
'success', ('ok', ''))
623
client.add_expected_call(
624
'BzrDir.find_repositoryV2', ('stacked/',),
625
'success', ('ok', '', 'no', 'no', 'no'))
626
# called twice, once from constructor and then again by us
627
client.add_expected_call(
628
'Branch.get_stacked_on_url', ('stacked/',),
629
'success', ('ok', '../base'))
630
client.add_expected_call(
631
'Branch.get_stacked_on_url', ('stacked/',),
632
'success', ('ok', '../base'))
633
bzrdir = RemoteBzrDir(self.get_transport('stacked'), _client=client)
634
branch = bzrdir.open_branch()
635
result = branch.get_stacked_on_url()
636
self.assertEqual('../base', result)
637
client.finished_test()
638
# it's in the fallback list both for the RemoteRepository and its vfs
640
self.assertEqual(1, len(branch.repository._fallback_repositories))
642
len(branch.repository._real_repository._fallback_repositories))
645
class TestBranchSetLastRevision(RemoteBranchTestCase):
441
class TestBranchSetLastRevision(tests.TestCase):
647
443
def test_set_empty(self):
648
444
# set_revision_history([]) is translated to calling
652
448
transport = transport.clone('branch')
654
450
client = FakeClient(transport.base)
655
client.add_expected_call(
656
'Branch.get_stacked_on_url', ('branch/',),
657
'error', ('NotStacked',))
658
client.add_expected_call(
659
'Branch.lock_write', ('branch/', '', ''),
660
'success', ('ok', 'branch token', 'repo token'))
661
client.add_expected_call(
662
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
664
client.add_expected_call(
665
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
667
branch = self.make_remote_branch(transport, client)
452
client.add_success_response('ok', 'branch token', 'repo token')
454
client.add_success_response('ok')
456
client.add_success_response('ok')
457
bzrdir = RemoteBzrDir(transport, _client=False)
458
branch = RemoteBranch(bzrdir, None, _client=client)
668
459
# This is a hack to work around the problem that RemoteBranch currently
669
460
# unnecessarily invokes _ensure_real upon a call to lock_write.
670
461
branch._ensure_real = lambda: None
671
462
branch.lock_write()
672
464
result = branch.set_revision_history([])
466
[('call', 'Branch.set_last_revision',
467
('branch/', 'branch token', 'repo token', 'null:'))],
674
470
self.assertEqual(None, result)
675
client.finished_test()
677
472
def test_set_nonempty(self):
678
473
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
682
477
transport = transport.clone('branch')
684
479
client = FakeClient(transport.base)
685
client.add_expected_call(
686
'Branch.get_stacked_on_url', ('branch/',),
687
'error', ('NotStacked',))
688
client.add_expected_call(
689
'Branch.lock_write', ('branch/', '', ''),
690
'success', ('ok', 'branch token', 'repo token'))
691
client.add_expected_call(
692
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
694
client.add_expected_call(
695
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
697
branch = self.make_remote_branch(transport, client)
481
client.add_success_response('ok', 'branch token', 'repo token')
483
client.add_success_response('ok')
485
client.add_success_response('ok')
486
bzrdir = RemoteBzrDir(transport, _client=False)
487
branch = RemoteBranch(bzrdir, None, _client=client)
698
488
# This is a hack to work around the problem that RemoteBranch currently
699
489
# unnecessarily invokes _ensure_real upon a call to lock_write.
700
490
branch._ensure_real = lambda: None
701
491
# Lock the branch, reset the record of remote calls.
702
492
branch.lock_write()
703
495
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
497
[('call', 'Branch.set_last_revision',
498
('branch/', 'branch token', 'repo token', 'rev-id2'))],
705
501
self.assertEqual(None, result)
706
client.finished_test()
708
503
def test_no_such_revision(self):
709
504
transport = MemoryTransport()
711
506
transport = transport.clone('branch')
712
507
# A response of 'NoSuchRevision' is translated into an exception.
713
508
client = FakeClient(transport.base)
714
client.add_expected_call(
715
'Branch.get_stacked_on_url', ('branch/',),
716
'error', ('NotStacked',))
717
client.add_expected_call(
718
'Branch.lock_write', ('branch/', '', ''),
719
'success', ('ok', 'branch token', 'repo token'))
720
client.add_expected_call(
721
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
722
'error', ('NoSuchRevision', 'rev-id'))
723
client.add_expected_call(
724
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
510
client.add_success_response('ok', 'branch token', 'repo token')
512
client.add_error_response('NoSuchRevision', 'rev-id')
514
client.add_success_response('ok')
727
branch = self.make_remote_branch(transport, client)
516
bzrdir = RemoteBzrDir(transport, _client=False)
517
branch = RemoteBranch(bzrdir, None, _client=client)
518
branch._ensure_real = lambda: None
728
519
branch.lock_write()
729
522
self.assertRaises(
730
523
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
732
client.finished_test()
734
def test_tip_change_rejected(self):
735
"""TipChangeRejected responses cause a TipChangeRejected exception to
738
transport = MemoryTransport()
739
transport.mkdir('branch')
740
transport = transport.clone('branch')
741
client = FakeClient(transport.base)
742
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
743
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
744
client.add_expected_call(
745
'Branch.get_stacked_on_url', ('branch/',),
746
'error', ('NotStacked',))
747
client.add_expected_call(
748
'Branch.lock_write', ('branch/', '', ''),
749
'success', ('ok', 'branch token', 'repo token'))
750
client.add_expected_call(
751
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
752
'error', ('TipChangeRejected', rejection_msg_utf8))
753
client.add_expected_call(
754
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
756
branch = self.make_remote_branch(transport, client)
757
branch._ensure_real = lambda: None
759
self.addCleanup(branch.unlock)
760
# The 'TipChangeRejected' error response triggered by calling
761
# set_revision_history causes a TipChangeRejected exception.
762
err = self.assertRaises(
763
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
764
# The UTF-8 message from the response has been decoded into a unicode
766
self.assertIsInstance(err.msg, unicode)
767
self.assertEqual(rejection_msg_unicode, err.msg)
769
client.finished_test()
772
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
527
class TestBranchSetLastRevisionInfo(tests.TestCase):
774
529
def test_set_last_revision_info(self):
775
530
# set_last_revision_info(num, 'rev-id') is translated to calling
895
643
client.add_success_response('ok')
897
branch = self.make_remote_branch(transport, client)
645
bzrdir = RemoteBzrDir(transport, _client=False)
646
branch = RemoteBranch(bzrdir, None, _client=client)
647
# This is a hack to work around the problem that RemoteBranch currently
648
# unnecessarily invokes _ensure_real upon a call to lock_write.
649
branch._ensure_real = lambda: None
898
650
# Lock the branch, reset the record of remote calls.
899
651
branch.lock_write()
900
652
client._calls = []
902
654
err = self.assertRaises(
903
errors.UnknownErrorFromSmartServer,
655
errors.ErrorFromSmartServer,
904
656
branch.set_last_revision_info, 123, 'revid')
905
657
self.assertEqual(('UnexpectedError',), err.error_tuple)
908
def test_tip_change_rejected(self):
909
"""TipChangeRejected responses cause a TipChangeRejected exception to
912
transport = MemoryTransport()
913
transport.mkdir('branch')
914
transport = transport.clone('branch')
915
client = FakeClient(transport.base)
917
client.add_error_response('NotStacked')
919
client.add_success_response('ok', 'branch token', 'repo token')
921
client.add_error_response('TipChangeRejected', 'rejection message')
923
client.add_success_response('ok')
925
branch = self.make_remote_branch(transport, client)
926
# Lock the branch, reset the record of remote calls.
928
self.addCleanup(branch.unlock)
931
# The 'TipChangeRejected' error response triggered by calling
932
# set_last_revision_info causes a TipChangeRejected exception.
933
err = self.assertRaises(
934
errors.TipChangeRejected,
935
branch.set_last_revision_info, 123, 'revid')
936
self.assertEqual('rejection message', err.msg)
939
661
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
940
662
"""Getting the branch configuration should use an abstract method not vfs.
1450
1155
src_repo.copy_content_into(dest_repo)
1453
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
1454
"""Base class for unit tests for bzrlib.remote._translate_error."""
1456
def translateTuple(self, error_tuple, **context):
1457
"""Call _translate_error with an ErrorFromSmartServer built from the
1460
:param error_tuple: A tuple of a smart server response, as would be
1461
passed to an ErrorFromSmartServer.
1462
:kwargs context: context items to call _translate_error with.
1464
:returns: The error raised by _translate_error.
1466
# Raise the ErrorFromSmartServer before passing it as an argument,
1467
# because _translate_error may need to re-raise it with a bare 'raise'
1469
server_error = errors.ErrorFromSmartServer(error_tuple)
1470
translated_error = self.translateErrorFromSmartServer(
1471
server_error, **context)
1472
return translated_error
1474
def translateErrorFromSmartServer(self, error_object, **context):
1475
"""Like translateTuple, but takes an already constructed
1476
ErrorFromSmartServer rather than a tuple.
1480
except errors.ErrorFromSmartServer, server_error:
1481
translated_error = self.assertRaises(
1482
errors.BzrError, remote._translate_error, server_error,
1484
return translated_error
1487
class TestErrorTranslationSuccess(TestErrorTranslationBase):
1488
"""Unit tests for bzrlib.remote._translate_error.
1490
Given an ErrorFromSmartServer (which has an error tuple from a smart
1491
server) and some context, _translate_error raises more specific errors from
1494
This test case covers the cases where _translate_error succeeds in
1495
translating an ErrorFromSmartServer to something better. See
1496
TestErrorTranslationRobustness for other cases.
1499
def test_NoSuchRevision(self):
1500
branch = self.make_branch('')
1502
translated_error = self.translateTuple(
1503
('NoSuchRevision', revid), branch=branch)
1504
expected_error = errors.NoSuchRevision(branch, revid)
1505
self.assertEqual(expected_error, translated_error)
1507
def test_nosuchrevision(self):
1508
repository = self.make_repository('')
1510
translated_error = self.translateTuple(
1511
('nosuchrevision', revid), repository=repository)
1512
expected_error = errors.NoSuchRevision(repository, revid)
1513
self.assertEqual(expected_error, translated_error)
1515
def test_nobranch(self):
1516
bzrdir = self.make_bzrdir('')
1517
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
1518
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
1519
self.assertEqual(expected_error, translated_error)
1521
def test_LockContention(self):
1522
translated_error = self.translateTuple(('LockContention',))
1523
expected_error = errors.LockContention('(remote lock)')
1524
self.assertEqual(expected_error, translated_error)
1526
def test_UnlockableTransport(self):
1527
bzrdir = self.make_bzrdir('')
1528
translated_error = self.translateTuple(
1529
('UnlockableTransport',), bzrdir=bzrdir)
1530
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
1531
self.assertEqual(expected_error, translated_error)
1533
def test_LockFailed(self):
1534
lock = 'str() of a server lock'
1535
why = 'str() of why'
1536
translated_error = self.translateTuple(('LockFailed', lock, why))
1537
expected_error = errors.LockFailed(lock, why)
1538
self.assertEqual(expected_error, translated_error)
1540
def test_TokenMismatch(self):
1541
token = 'a lock token'
1542
translated_error = self.translateTuple(('TokenMismatch',), token=token)
1543
expected_error = errors.TokenMismatch(token, '(remote token)')
1544
self.assertEqual(expected_error, translated_error)
1546
def test_Diverged(self):
1547
branch = self.make_branch('a')
1548
other_branch = self.make_branch('b')
1549
translated_error = self.translateTuple(
1550
('Diverged',), branch=branch, other_branch=other_branch)
1551
expected_error = errors.DivergedBranches(branch, other_branch)
1552
self.assertEqual(expected_error, translated_error)
1555
class TestErrorTranslationRobustness(TestErrorTranslationBase):
1556
"""Unit tests for bzrlib.remote._translate_error's robustness.
1558
TestErrorTranslationSuccess is for cases where _translate_error can
1559
translate successfully. This class about how _translate_err behaves when
1560
it fails to translate: it re-raises the original error.
1563
def test_unrecognised_server_error(self):
1564
"""If the error code from the server is not recognised, the original
1565
ErrorFromSmartServer is propagated unmodified.
1567
error_tuple = ('An unknown error tuple',)
1568
server_error = errors.ErrorFromSmartServer(error_tuple)
1569
translated_error = self.translateErrorFromSmartServer(server_error)
1570
expected_error = errors.UnknownErrorFromSmartServer(server_error)
1571
self.assertEqual(expected_error, translated_error)
1573
def test_context_missing_a_key(self):
1574
"""In case of a bug in the client, or perhaps an unexpected response
1575
from a server, _translate_error returns the original error tuple from
1576
the server and mutters a warning.
1578
# To translate a NoSuchRevision error _translate_error needs a 'branch'
1579
# in the context dict. So let's give it an empty context dict instead
1580
# to exercise its error recovery.
1582
error_tuple = ('NoSuchRevision', 'revid')
1583
server_error = errors.ErrorFromSmartServer(error_tuple)
1584
translated_error = self.translateErrorFromSmartServer(server_error)
1585
self.assertEqual(server_error, translated_error)
1586
# In addition to re-raising ErrorFromSmartServer, some debug info has
1587
# been muttered to the log file for developer to look at.
1588
self.assertContainsRe(
1589
self._get_log(keep_log_file=True),
1590
"Missing key 'branch' in context")
1158
class TestRepositoryStreamKnitData(TestRemoteRepository):
1160
def make_pack_file(self, records):
1161
pack_file = StringIO()
1162
pack_writer = pack.ContainerWriter(pack_file.write)
1164
for bytes, names in records:
1165
pack_writer.add_bytes_record(bytes, names)
1170
def make_pack_stream(self, records):
1171
pack_serialiser = pack.ContainerSerialiser()
1172
yield pack_serialiser.begin()
1173
for bytes, names in records:
1174
yield pack_serialiser.bytes_record(bytes, names)
1175
yield pack_serialiser.end()
1177
def test_bad_pack_from_server(self):
1178
"""A response with invalid data (e.g. it has a record with multiple
1179
names) triggers an exception.
1593
class TestStacking(tests.TestCaseWithTransport):
1594
"""Tests for operations on stacked remote repositories.
1181
Not all possible errors will be caught at this stage, but obviously
1182
malformed data should be.
1184
record = ('bytes', [('name1',), ('name2',)])
1185
pack_stream = self.make_pack_stream([record])
1186
transport_path = 'quack'
1187
repo, client = self.setup_fake_client_and_repository(transport_path)
1188
client.add_success_response_with_body(pack_stream, 'ok')
1189
search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
1190
stream = repo.get_data_stream_for_search(search)
1191
self.assertRaises(errors.SmartProtocolError, list, stream)
1596
The underlying format type must support stacking.
1599
def test_access_stacked_remote(self):
1600
# based on <http://launchpad.net/bugs/261315>
1601
# make a branch stacked on another repository containing an empty
1602
# revision, then open it over hpss - we should be able to see that
1604
base_transport = self.get_transport()
1605
base_builder = self.make_branch_builder('base', format='1.6')
1606
base_builder.start_series()
1607
base_revid = base_builder.build_snapshot('rev-id', None,
1608
[('add', ('', None, 'directory', None))],
1610
base_builder.finish_series()
1611
stacked_branch = self.make_branch('stacked', format='1.6')
1612
stacked_branch.set_stacked_on_url('../base')
1613
# start a server looking at this
1614
smart_server = server.SmartTCPServer_for_testing()
1615
smart_server.setUp()
1616
self.addCleanup(smart_server.tearDown)
1617
remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
1618
# can get its branch and repository
1619
remote_branch = remote_bzrdir.open_branch()
1620
remote_repo = remote_branch.repository
1621
remote_repo.lock_read()
1623
# it should have an appropriate fallback repository, which should also
1624
# be a RemoteRepository
1625
self.assertEquals(len(remote_repo._fallback_repositories), 1)
1626
self.assertIsInstance(remote_repo._fallback_repositories[0],
1628
# and it has the revision committed to the underlying repository;
1629
# these have varying implementations so we try several of them
1630
self.assertTrue(remote_repo.has_revisions([base_revid]))
1631
self.assertTrue(remote_repo.has_revision(base_revid))
1632
self.assertEqual(remote_repo.get_revision(base_revid).message,
1635
remote_repo.unlock()
1193
def test_backwards_compatibility(self):
1194
"""If the server doesn't recognise this request, fallback to VFS."""
1195
repo, client = self.setup_fake_client_and_repository('path')
1196
client.add_unknown_method_response(
1197
'Repository.stream_revisions_chunked')
1198
self.mock_called = False
1199
repo._real_repository = MockRealRepository(self)
1200
search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
1201
repo.get_data_stream_for_search(search)
1202
self.assertTrue(self.mock_called)
1203
self.failIf(client.expecting_body,
1204
"The protocol has been left in an unclean state that will cause "
1205
"TooManyConcurrentRequests errors.")
1208
class MockRealRepository(object):
1209
"""Helper class for TestRepositoryStreamKnitData.test_unknown_method."""
1211
def __init__(self, test):
1214
def get_data_stream_for_search(self, search):
1215
self.test.assertEqual(set(['revid']), search.get_keys())
1216
self.test.mock_called = True