113
131
b = BzrDir.open_from_transport(self.transport).open_branch()
114
132
self.assertStartsWith(str(b), 'RemoteBranch(')
134
def test_remote_branch_format_supports_stacking(self):
136
self.make_branch('unstackable', format='pack-0.92')
137
b = BzrDir.open_from_transport(t.clone('unstackable')).open_branch()
138
self.assertFalse(b._format.supports_stacking())
139
self.make_branch('stackable', format='1.9')
140
b = BzrDir.open_from_transport(t.clone('stackable')).open_branch()
141
self.assertTrue(b._format.supports_stacking())
143
def test_remote_repo_format_supports_external_references(self):
145
bd = self.make_bzrdir('unstackable', format='pack-0.92')
146
r = bd.create_repository()
147
self.assertFalse(r._format.supports_external_lookups)
148
r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
149
self.assertFalse(r._format.supports_external_lookups)
150
bd = self.make_bzrdir('stackable', format='1.9')
151
r = bd.create_repository()
152
self.assertTrue(r._format.supports_external_lookups)
153
r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
154
self.assertTrue(r._format.supports_external_lookups)
117
157
class FakeProtocol(object):
118
158
"""Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
345
397
AssertionError, client_medium._remember_remote_is_before, (1, 9))
348
class TestBzrDirOpenBranch(tests.TestCase):
400
class TestBzrDirCloningMetaDir(TestRemote):
402
def test_backwards_compat(self):
403
self.setup_smart_server_with_call_log()
404
a_dir = self.make_bzrdir('.')
405
self.reset_smart_call_log()
406
verb = 'BzrDir.cloning_metadir'
407
self.disable_verb(verb)
408
format = a_dir.cloning_metadir()
409
call_count = len([call for call in self.hpss_calls if
410
call.call.method == verb])
411
self.assertEqual(1, call_count)
413
def test_branch_reference(self):
414
transport = self.get_transport('quack')
415
referenced = self.make_branch('referenced')
416
expected = referenced.bzrdir.cloning_metadir()
417
client = FakeClient(transport.base)
418
client.add_expected_call(
419
'BzrDir.cloning_metadir', ('quack/', 'False'),
420
'error', ('BranchReference',)),
421
client.add_expected_call(
422
'BzrDir.open_branchV2', ('quack/',),
423
'success', ('ref', self.get_url('referenced'))),
424
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
426
result = a_bzrdir.cloning_metadir()
427
# We should have got a control dir matching the referenced branch.
428
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
429
self.assertEqual(expected._repository_format, result._repository_format)
430
self.assertEqual(expected._branch_format, result._branch_format)
431
client.finished_test()
433
def test_current_server(self):
434
transport = self.get_transport('.')
435
transport = transport.clone('quack')
436
self.make_bzrdir('quack')
437
client = FakeClient(transport.base)
438
reference_bzrdir_format = bzrdir.format_registry.get('default')()
439
control_name = reference_bzrdir_format.network_name()
440
client.add_expected_call(
441
'BzrDir.cloning_metadir', ('quack/', 'False'),
442
'success', (control_name, '', ('branch', ''))),
443
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
445
result = a_bzrdir.cloning_metadir()
446
# We should have got a reference control dir with default branch and
447
# repository formats.
448
# This pokes a little, just to be sure.
449
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
450
self.assertEqual(None, result._repository_format)
451
self.assertEqual(None, result._branch_format)
452
client.finished_test()
455
class TestBzrDirOpenBranch(TestRemote):
457
def test_backwards_compat(self):
458
self.setup_smart_server_with_call_log()
459
self.make_branch('.')
460
a_dir = BzrDir.open(self.get_url('.'))
461
self.reset_smart_call_log()
462
verb = 'BzrDir.open_branchV2'
463
self.disable_verb(verb)
464
format = a_dir.open_branch()
465
call_count = len([call for call in self.hpss_calls if
466
call.call.method == verb])
467
self.assertEqual(1, call_count)
350
469
def test_branch_present(self):
470
reference_format = self.get_repo_format()
471
network_name = reference_format.network_name()
472
branch_network_name = self.get_branch_format().network_name()
351
473
transport = MemoryTransport()
352
474
transport.mkdir('quack')
353
475
transport = transport.clone('quack')
354
476
client = FakeClient(transport.base)
355
477
client.add_expected_call(
356
'BzrDir.open_branch', ('quack/',),
357
'success', ('ok', ''))
478
'BzrDir.open_branchV2', ('quack/',),
479
'success', ('branch', branch_network_name))
358
480
client.add_expected_call(
359
'BzrDir.find_repositoryV2', ('quack/',),
360
'success', ('ok', '', 'no', 'no', 'no'))
481
'BzrDir.find_repositoryV3', ('quack/',),
482
'success', ('ok', '', 'no', 'no', 'no', network_name))
361
483
client.add_expected_call(
362
484
'Branch.get_stacked_on_url', ('quack/',),
363
485
'error', ('NotStacked',))
404
526
# transmitted as "~", not "%7E".
405
527
transport = RemoteTCPTransport('bzr://localhost/~hello/')
406
528
client = FakeClient(transport.base)
407
client.add_expected_call(
408
'BzrDir.open_branch', ('~hello/',),
409
'success', ('ok', ''))
410
client.add_expected_call(
411
'BzrDir.find_repositoryV2', ('~hello/',),
412
'success', ('ok', '', 'no', 'no', 'no'))
529
reference_format = self.get_repo_format()
530
network_name = reference_format.network_name()
531
branch_network_name = self.get_branch_format().network_name()
532
client.add_expected_call(
533
'BzrDir.open_branchV2', ('~hello/',),
534
'success', ('branch', branch_network_name))
535
client.add_expected_call(
536
'BzrDir.find_repositoryV3', ('~hello/',),
537
'success', ('ok', '', 'no', 'no', 'no', network_name))
413
538
client.add_expected_call(
414
539
'Branch.get_stacked_on_url', ('~hello/',),
415
540
'error', ('NotStacked',))
432
559
subtree_response = 'no'
433
560
client = FakeClient(transport.base)
434
561
client.add_success_response(
435
'ok', '', rich_response, subtree_response, external_lookup)
562
'ok', '', rich_response, subtree_response, external_lookup,
436
564
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
438
566
result = bzrdir.open_repository()
439
567
self.assertEqual(
440
[('call', 'BzrDir.find_repositoryV2', ('quack/',))],
568
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
442
570
self.assertIsInstance(result, RemoteRepository)
443
571
self.assertEqual(bzrdir, result.bzrdir)
459
587
RemoteBzrDirFormat.probe_transport, OldServerTransport())
590
class TestBzrDirCreateBranch(TestRemote):
592
def test_backwards_compat(self):
593
self.setup_smart_server_with_call_log()
594
repo = self.make_repository('.')
595
self.reset_smart_call_log()
596
self.disable_verb('BzrDir.create_branch')
597
branch = repo.bzrdir.create_branch()
598
create_branch_call_count = len([call for call in self.hpss_calls if
599
call.call.method == 'BzrDir.create_branch'])
600
self.assertEqual(1, create_branch_call_count)
602
def test_current_server(self):
603
transport = self.get_transport('.')
604
transport = transport.clone('quack')
605
self.make_repository('quack')
606
client = FakeClient(transport.base)
607
reference_bzrdir_format = bzrdir.format_registry.get('default')()
608
reference_format = reference_bzrdir_format.get_branch_format()
609
network_name = reference_format.network_name()
610
reference_repo_fmt = reference_bzrdir_format.repository_format
611
reference_repo_name = reference_repo_fmt.network_name()
612
client.add_expected_call(
613
'BzrDir.create_branch', ('quack/', network_name),
614
'success', ('ok', network_name, '', 'no', 'no', 'yes',
615
reference_repo_name))
616
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
618
branch = a_bzrdir.create_branch()
619
# We should have got a remote branch
620
self.assertIsInstance(branch, remote.RemoteBranch)
621
# its format should have the settings from the response
622
format = branch._format
623
self.assertEqual(network_name, format.network_name())
462
626
class TestBzrDirCreateRepository(TestRemote):
464
628
def test_backwards_compat(self):
496
660
self.assertEqual(network_name, format.network_name())
499
class TestBzrDirOpenRepository(tests.TestCase):
663
class TestBzrDirOpenRepository(TestRemote):
501
def test_backwards_compat_1_2(self):
502
transport = MemoryTransport()
503
transport.mkdir('quack')
504
transport = transport.clone('quack')
505
client = FakeClient(transport.base)
665
def test_backwards_compat_1_2_3(self):
666
# fallback all the way to the first version.
667
reference_format = self.get_repo_format()
668
network_name = reference_format.network_name()
669
client = FakeClient('bzr://example.com/')
670
client.add_unknown_method_response('BzrDir.find_repositoryV3')
506
671
client.add_unknown_method_response('BzrDir.find_repositoryV2')
507
672
client.add_success_response('ok', '', 'no', 'no')
673
# A real repository instance will be created to determine the network
675
client.add_success_response_with_body(
676
"Bazaar-NG meta directory, format 1\n", 'ok')
677
client.add_success_response_with_body(
678
reference_format.get_format_string(), 'ok')
679
# PackRepository wants to do a stat
680
client.add_success_response('stat', '0', '65535')
681
remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
683
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
685
repo = bzrdir.open_repository()
687
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
688
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
689
('call', 'BzrDir.find_repository', ('quack/',)),
690
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
691
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
692
('call', 'stat', ('/quack/.bzr/repository',)),
695
self.assertEqual(network_name, repo._format.network_name())
697
def test_backwards_compat_2(self):
698
# fallback to find_repositoryV2
699
reference_format = self.get_repo_format()
700
network_name = reference_format.network_name()
701
client = FakeClient('bzr://example.com/')
702
client.add_unknown_method_response('BzrDir.find_repositoryV3')
703
client.add_success_response('ok', '', 'no', 'no', 'no')
704
# A real repository instance will be created to determine the network
706
client.add_success_response_with_body(
707
"Bazaar-NG meta directory, format 1\n", 'ok')
708
client.add_success_response_with_body(
709
reference_format.get_format_string(), 'ok')
710
# PackRepository wants to do a stat
711
client.add_success_response('stat', '0', '65535')
712
remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
714
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
716
repo = bzrdir.open_repository()
718
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
719
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
720
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
721
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
722
('call', 'stat', ('/quack/.bzr/repository',)),
725
self.assertEqual(network_name, repo._format.network_name())
727
def test_current_server(self):
728
reference_format = self.get_repo_format()
729
network_name = reference_format.network_name()
730
transport = MemoryTransport()
731
transport.mkdir('quack')
732
transport = transport.clone('quack')
733
client = FakeClient(transport.base)
734
client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
508
735
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
510
737
repo = bzrdir.open_repository()
511
738
self.assertEqual(
512
[('call', 'BzrDir.find_repositoryV2', ('quack/',)),
513
('call', 'BzrDir.find_repository', ('quack/',))],
739
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
741
self.assertEqual(network_name, repo._format.network_name())
517
744
class OldSmartClient(object):
556
783
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
558
785
repo = RemoteRepository(bzrdir, None, _client=client)
559
return RemoteBranch(bzrdir, repo, _client=client)
786
branch_format = self.get_branch_format()
787
format = RemoteBranchFormat(network_name=branch_format.network_name())
788
return RemoteBranch(bzrdir, repo, _client=client, format=format)
791
class TestBranchGetParent(RemoteBranchTestCase):
793
def test_no_parent(self):
794
# in an empty branch we decode the response properly
795
transport = MemoryTransport()
796
client = FakeClient(transport.base)
797
client.add_expected_call(
798
'Branch.get_stacked_on_url', ('quack/',),
799
'error', ('NotStacked',))
800
client.add_expected_call(
801
'Branch.get_parent', ('quack/',),
803
transport.mkdir('quack')
804
transport = transport.clone('quack')
805
branch = self.make_remote_branch(transport, client)
806
result = branch.get_parent()
807
client.finished_test()
808
self.assertEqual(None, result)
810
def test_parent_relative(self):
811
transport = MemoryTransport()
812
client = FakeClient(transport.base)
813
client.add_expected_call(
814
'Branch.get_stacked_on_url', ('kwaak/',),
815
'error', ('NotStacked',))
816
client.add_expected_call(
817
'Branch.get_parent', ('kwaak/',),
818
'success', ('../foo/',))
819
transport.mkdir('kwaak')
820
transport = transport.clone('kwaak')
821
branch = self.make_remote_branch(transport, client)
822
result = branch.get_parent()
823
self.assertEqual(transport.clone('../foo').base, result)
825
def test_parent_absolute(self):
826
transport = MemoryTransport()
827
client = FakeClient(transport.base)
828
client.add_expected_call(
829
'Branch.get_stacked_on_url', ('kwaak/',),
830
'error', ('NotStacked',))
831
client.add_expected_call(
832
'Branch.get_parent', ('kwaak/',),
833
'success', ('http://foo/',))
834
transport.mkdir('kwaak')
835
transport = transport.clone('kwaak')
836
branch = self.make_remote_branch(transport, client)
837
result = branch.get_parent()
838
self.assertEqual('http://foo/', result)
841
class TestBranchGetTagsBytes(RemoteBranchTestCase):
843
def test_backwards_compat(self):
844
self.setup_smart_server_with_call_log()
845
branch = self.make_branch('.')
846
self.reset_smart_call_log()
847
verb = 'Branch.get_tags_bytes'
848
self.disable_verb(verb)
849
branch.tags.get_tag_dict()
850
call_count = len([call for call in self.hpss_calls if
851
call.call.method == verb])
852
self.assertEqual(1, call_count)
854
def test_trivial(self):
855
transport = MemoryTransport()
856
client = FakeClient(transport.base)
857
client.add_expected_call(
858
'Branch.get_stacked_on_url', ('quack/',),
859
'error', ('NotStacked',))
860
client.add_expected_call(
861
'Branch.get_tags_bytes', ('quack/',),
863
transport.mkdir('quack')
864
transport = transport.clone('quack')
865
branch = self.make_remote_branch(transport, client)
866
result = branch.tags.get_tag_dict()
867
client.finished_test()
868
self.assertEqual({}, result)
562
871
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
632
943
stacked_branch = self.make_branch('stacked', format='1.6')
633
944
stacked_branch.set_stacked_on_url('../base')
634
945
client = FakeClient(self.get_url())
635
client.add_expected_call(
636
'BzrDir.open_branch', ('stacked/',),
637
'success', ('ok', ''))
638
client.add_expected_call(
639
'BzrDir.find_repositoryV2', ('stacked/',),
640
'success', ('ok', '', 'no', 'no', 'no'))
946
branch_network_name = self.get_branch_format().network_name()
947
client.add_expected_call(
948
'BzrDir.open_branchV2', ('stacked/',),
949
'success', ('branch', branch_network_name))
950
client.add_expected_call(
951
'BzrDir.find_repositoryV3', ('stacked/',),
952
'success', ('ok', '', 'no', 'no', 'yes',
953
stacked_branch.repository._format.network_name()))
641
954
# called twice, once from constructor and then again by us
642
955
client.add_expected_call(
643
956
'Branch.get_stacked_on_url', ('stacked/',),
663
976
base_branch = self.make_branch('base', format='1.6')
664
977
stacked_branch = self.make_branch('stacked', format='1.6')
665
978
stacked_branch.set_stacked_on_url('../base')
979
reference_format = self.get_repo_format()
980
network_name = reference_format.network_name()
666
981
client = FakeClient(self.get_url())
667
client.add_expected_call(
668
'BzrDir.open_branch', ('stacked/',),
669
'success', ('ok', ''))
670
client.add_expected_call(
671
'BzrDir.find_repositoryV2', ('stacked/',),
672
'success', ('ok', '', 'no', 'no', 'no'))
982
branch_network_name = self.get_branch_format().network_name()
983
client.add_expected_call(
984
'BzrDir.open_branchV2', ('stacked/',),
985
'success', ('branch', branch_network_name))
986
client.add_expected_call(
987
'BzrDir.find_repositoryV3', ('stacked/',),
988
'success', ('ok', '', 'no', 'no', 'yes', network_name))
673
989
# called twice, once from constructor and then again by us
674
990
client.add_expected_call(
675
991
'Branch.get_stacked_on_url', ('stacked/',),
1018
1332
self.assertEqual('rejection message', err.msg)
1021
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
1022
"""Getting the branch configuration should use an abstract method not vfs.
1335
class TestBranchGetSetConfig(RemoteBranchTestCase):
1025
1337
def test_get_branch_conf(self):
1026
raise tests.KnownFailure('branch.conf is not retrieved by get_config_file')
1027
## # We should see that branch.get_config() does a single rpc to get the
1028
## # remote configuration file, abstracting away where that is stored on
1029
## # the server. However at the moment it always falls back to using the
1030
## # vfs, and this would need some changes in config.py.
1032
## # in an empty branch we decode the response properly
1033
## client = FakeClient([(('ok', ), '# config file body')], self.get_url())
1034
## # we need to make a real branch because the remote_branch.control_files
1035
## # will trigger _ensure_real.
1036
## branch = self.make_branch('quack')
1037
## transport = branch.bzrdir.root_transport
1038
## # we do not want bzrdir to make any remote calls
1039
## bzrdir = RemoteBzrDir(transport, _client=False)
1040
## branch = RemoteBranch(bzrdir, None, _client=client)
1041
## config = branch.get_config()
1042
## self.assertEqual(
1043
## [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
1338
# in an empty branch we decode the response properly
1339
client = FakeClient()
1340
client.add_expected_call(
1341
'Branch.get_stacked_on_url', ('memory:///',),
1342
'error', ('NotStacked',),)
1343
client.add_success_response_with_body('# config file body', 'ok')
1344
transport = MemoryTransport()
1345
branch = self.make_remote_branch(transport, client)
1346
config = branch.get_config()
1347
config.has_explicit_nickname()
1349
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1350
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1353
def test_get_multi_line_branch_conf(self):
1354
# Make sure that multiple-line branch.conf files are supported
1356
# https://bugs.edge.launchpad.net/bzr/+bug/354075
1357
client = FakeClient()
1358
client.add_expected_call(
1359
'Branch.get_stacked_on_url', ('memory:///',),
1360
'error', ('NotStacked',),)
1361
client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
1362
transport = MemoryTransport()
1363
branch = self.make_remote_branch(transport, client)
1364
config = branch.get_config()
1365
self.assertEqual(u'2', config.get_user_option('b'))
1367
def test_set_option(self):
1368
client = FakeClient()
1369
client.add_expected_call(
1370
'Branch.get_stacked_on_url', ('memory:///',),
1371
'error', ('NotStacked',),)
1372
client.add_expected_call(
1373
'Branch.lock_write', ('memory:///', '', ''),
1374
'success', ('ok', 'branch token', 'repo token'))
1375
client.add_expected_call(
1376
'Branch.set_config_option', ('memory:///', 'branch token',
1377
'repo token', 'foo', 'bar', ''),
1379
client.add_expected_call(
1380
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1382
transport = MemoryTransport()
1383
branch = self.make_remote_branch(transport, client)
1385
config = branch._get_config()
1386
config.set_option('foo', 'bar')
1388
client.finished_test()
1390
def test_backwards_compat_set_option(self):
1391
self.setup_smart_server_with_call_log()
1392
branch = self.make_branch('.')
1393
verb = 'Branch.set_config_option'
1394
self.disable_verb(verb)
1396
self.addCleanup(branch.unlock)
1397
self.reset_smart_call_log()
1398
branch._get_config().set_option('value', 'name')
1399
self.assertLength(10, self.hpss_calls)
1400
self.assertEqual('value', branch._get_config().get_option('name'))
1047
1403
class TestBranchLockWrite(RemoteBranchTestCase):
1261
1631
self.assertEqual({r1: (NULL_REVISION,)}, parents)
1262
1632
self.assertEqual(
1263
1633
[('call_with_body_bytes_expecting_body',
1264
'Repository.get_parent_map', ('quack/', r2), '\n\n0'),
1634
'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1265
1636
('call_with_body_bytes_expecting_body',
1266
'Repository.get_parent_map', ('quack/', r1), '\n\n0'),
1637
'Repository.get_parent_map', ('quack/', 'include-missing:', r1),
1271
1643
def test_get_parent_map_reconnects_if_unknown_method(self):
1272
1644
transport_path = 'quack'
1645
rev_id = 'revision-id'
1273
1646
repo, client = self.setup_fake_client_and_repository(transport_path)
1274
client.add_unknown_method_response('Repository,get_parent_map')
1275
client.add_success_response_with_body('', 'ok')
1647
client.add_unknown_method_response('Repository.get_parent_map')
1648
client.add_success_response_with_body(rev_id, 'ok')
1276
1649
self.assertFalse(client._medium._is_remote_before((1, 2)))
1277
rev_id = 'revision-id'
1278
expected_deprecations = [
1279
'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
1281
parents = self.callDeprecated(
1282
expected_deprecations, repo.get_parent_map, [rev_id])
1650
parents = repo.get_parent_map([rev_id])
1283
1651
self.assertEqual(
1284
1652
[('call_with_body_bytes_expecting_body',
1285
'Repository.get_parent_map', ('quack/', rev_id), '\n\n0'),
1653
'Repository.get_parent_map', ('quack/', 'include-missing:',
1286
1655
('disconnect medium',),
1287
1656
('call_expecting_body', 'Repository.get_revision_graph',
1288
1657
('quack/', ''))],
1290
1659
# The medium is now marked as being connected to an older server
1291
1660
self.assertTrue(client._medium._is_remote_before((1, 2)))
1661
self.assertEqual({rev_id: ('null:',)}, parents)
1293
1663
def test_get_parent_map_fallback_parentless_node(self):
1294
1664
"""get_parent_map falls back to get_revision_graph on old servers. The
1324
1690
errors.UnexpectedSmartServerResponse,
1325
1691
repo.get_parent_map, ['a-revision-id'])
1693
def test_get_parent_map_negative_caches_missing_keys(self):
1694
self.setup_smart_server_with_call_log()
1695
repo = self.make_repository('foo')
1696
self.assertIsInstance(repo, RemoteRepository)
1698
self.addCleanup(repo.unlock)
1699
self.reset_smart_call_log()
1700
graph = repo.get_graph()
1701
self.assertEqual({},
1702
graph.get_parent_map(['some-missing', 'other-missing']))
1703
self.assertLength(1, self.hpss_calls)
1704
# No call if we repeat this
1705
self.reset_smart_call_log()
1706
graph = repo.get_graph()
1707
self.assertEqual({},
1708
graph.get_parent_map(['some-missing', 'other-missing']))
1709
self.assertLength(0, self.hpss_calls)
1710
# Asking for more unknown keys makes a request.
1711
self.reset_smart_call_log()
1712
graph = repo.get_graph()
1713
self.assertEqual({},
1714
graph.get_parent_map(['some-missing', 'other-missing',
1716
self.assertLength(1, self.hpss_calls)
1718
def disableExtraResults(self):
1719
old_flag = SmartServerRepositoryGetParentMap.no_extra_results
1720
SmartServerRepositoryGetParentMap.no_extra_results = True
1722
SmartServerRepositoryGetParentMap.no_extra_results = old_flag
1723
self.addCleanup(reset_values)
1725
def test_null_cached_missing_and_stop_key(self):
1726
self.setup_smart_server_with_call_log()
1727
# Make a branch with a single revision.
1728
builder = self.make_branch_builder('foo')
1729
builder.start_series()
1730
builder.build_snapshot('first', None, [
1731
('add', ('', 'root-id', 'directory', ''))])
1732
builder.finish_series()
1733
branch = builder.get_branch()
1734
repo = branch.repository
1735
self.assertIsInstance(repo, RemoteRepository)
1736
# Stop the server from sending extra results.
1737
self.disableExtraResults()
1739
self.addCleanup(repo.unlock)
1740
self.reset_smart_call_log()
1741
graph = repo.get_graph()
1742
# Query for 'first' and 'null:'. Because 'null:' is a parent of
1743
# 'first' it will be a candidate for the stop_keys of subsequent
1744
# requests, and because 'null:' was queried but not returned it will be
1745
# cached as missing.
1746
self.assertEqual({'first': ('null:',)},
1747
graph.get_parent_map(['first', 'null:']))
1748
# Now query for another key. This request will pass along a recipe of
1749
# start and stop keys describing the already cached results, and this
1750
# recipe's revision count must be correct (or else it will trigger an
1751
# error from the server).
1752
self.assertEqual({}, graph.get_parent_map(['another-key']))
1753
# This assertion guards against disableExtraResults silently failing to
1754
# work, thus invalidating the test.
1755
self.assertLength(2, self.hpss_calls)
1757
def test_get_parent_map_gets_ghosts_from_result(self):
1758
# asking for a revision should negatively cache close ghosts in its
1760
self.setup_smart_server_with_call_log()
1761
tree = self.make_branch_and_memory_tree('foo')
1764
builder = treebuilder.TreeBuilder()
1765
builder.start_tree(tree)
1767
builder.finish_tree()
1768
tree.set_parent_ids(['non-existant'], allow_leftmost_as_ghost=True)
1769
rev_id = tree.commit('')
1773
self.addCleanup(tree.unlock)
1774
repo = tree.branch.repository
1775
self.assertIsInstance(repo, RemoteRepository)
1777
repo.get_parent_map([rev_id])
1778
self.reset_smart_call_log()
1779
# Now asking for rev_id's ghost parent should not make calls
1780
self.assertEqual({}, repo.get_parent_map(['non-existant']))
1781
self.assertLength(0, self.hpss_calls)
1328
1784
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
1537
1996
self.assertEqual([], client._calls)
1999
class TestRepositoryInsertStream(TestRemoteRepository):
2001
def test_unlocked_repo(self):
2002
transport_path = 'quack'
2003
repo, client = self.setup_fake_client_and_repository(transport_path)
2004
client.add_expected_call(
2005
'Repository.insert_stream', ('quack/', ''),
2007
client.add_expected_call(
2008
'Repository.insert_stream', ('quack/', ''),
2010
sink = repo._get_sink()
2011
fmt = repository.RepositoryFormat.get_default_format()
2012
resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2013
self.assertEqual([], resume_tokens)
2014
self.assertEqual(set(), missing_keys)
2015
client.finished_test()
2017
def test_locked_repo_with_no_lock_token(self):
2018
transport_path = 'quack'
2019
repo, client = self.setup_fake_client_and_repository(transport_path)
2020
client.add_expected_call(
2021
'Repository.lock_write', ('quack/', ''),
2022
'success', ('ok', ''))
2023
client.add_expected_call(
2024
'Repository.insert_stream', ('quack/', ''),
2026
client.add_expected_call(
2027
'Repository.insert_stream', ('quack/', ''),
2030
sink = repo._get_sink()
2031
fmt = repository.RepositoryFormat.get_default_format()
2032
resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2033
self.assertEqual([], resume_tokens)
2034
self.assertEqual(set(), missing_keys)
2035
client.finished_test()
2037
def test_locked_repo_with_lock_token(self):
2038
transport_path = 'quack'
2039
repo, client = self.setup_fake_client_and_repository(transport_path)
2040
client.add_expected_call(
2041
'Repository.lock_write', ('quack/', ''),
2042
'success', ('ok', 'a token'))
2043
client.add_expected_call(
2044
'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2046
client.add_expected_call(
2047
'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2050
sink = repo._get_sink()
2051
fmt = repository.RepositoryFormat.get_default_format()
2052
resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2053
self.assertEqual([], resume_tokens)
2054
self.assertEqual(set(), missing_keys)
2055
client.finished_test()
1540
2058
class TestRepositoryTarball(TestRemoteRepository):
1542
2060
# This is a canned tarball reponse we can validate against
1900
2422
remote_repo.unlock()
1902
2424
def prepare_stacked_remote_branch(self):
1903
smart_server = server.SmartTCPServer_for_testing()
1904
smart_server.setUp()
1905
self.addCleanup(smart_server.tearDown)
1906
tree1 = self.make_branch_and_tree('tree1')
2425
"""Get stacked_upon and stacked branches with content in each."""
2426
self.setup_smart_server_with_call_log()
2427
tree1 = self.make_branch_and_tree('tree1', format='1.9')
1907
2428
tree1.commit('rev1', rev_id='rev1')
1908
tree2 = self.make_branch_and_tree('tree2', format='1.6')
1909
tree2.branch.set_stacked_on_url(tree1.branch.base)
1910
branch2 = Branch.open(smart_server.get_url() + '/tree2')
2429
tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2430
).open_workingtree()
2431
tree2.commit('local changes make me feel good.')
2432
branch2 = Branch.open(self.get_url('tree2'))
1911
2433
branch2.lock_read()
1912
2434
self.addCleanup(branch2.unlock)
2435
return tree1.branch, branch2
1915
2437
def test_stacked_get_parent_map(self):
1916
2438
# the public implementation of get_parent_map obeys stacking
1917
branch = self.prepare_stacked_remote_branch()
2439
_, branch = self.prepare_stacked_remote_branch()
1918
2440
repo = branch.repository
1919
2441
self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
1921
2443
def test_unstacked_get_parent_map(self):
1922
2444
# _unstacked_provider.get_parent_map ignores stacking
1923
branch = self.prepare_stacked_remote_branch()
2445
_, branch = self.prepare_stacked_remote_branch()
1924
2446
provider = branch.repository._unstacked_provider
1925
2447
self.assertEqual([], provider.get_parent_map(['rev1']).keys())
2449
def fetch_stream_to_rev_order(self, stream):
2451
for kind, substream in stream:
2452
if not kind == 'revisions':
2455
for content in substream:
2456
result.append(content.key[-1])
2459
def get_ordered_revs(self, format, order):
2460
"""Get a list of the revisions in a stream to format format.
2462
:param format: The format of the target.
2463
:param order: the order that target should have requested.
2464
:result: The revision ids in the stream, in the order seen,
2465
the topological order of revisions in the source.
2467
unordered_format = bzrdir.format_registry.get(format)()
2468
target_repository_format = unordered_format.repository_format
2470
self.assertEqual(order, target_repository_format._fetch_order)
2471
trunk, stacked = self.prepare_stacked_remote_branch()
2472
source = stacked.repository._get_source(target_repository_format)
2473
tip = stacked.last_revision()
2474
revs = stacked.repository.get_ancestry(tip)
2475
search = graph.PendingAncestryResult([tip], stacked.repository)
2476
self.reset_smart_call_log()
2477
stream = source.get_stream(search)
2480
# We trust that if a revision is in the stream the rest of the new
2481
# content for it is too, as per our main fetch tests; here we are
2482
# checking that the revisions are actually included at all, and their
2484
return self.fetch_stream_to_rev_order(stream), revs
2486
def test_stacked_get_stream_unordered(self):
2487
# Repository._get_source.get_stream() from a stacked repository with
2488
# unordered yields the full data from both stacked and stacked upon
2490
rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered')
2491
self.assertEqual(set(expected_revs), set(rev_ord))
2492
# Getting unordered results should have made a streaming data request
2493
# from the server, then one from the backing branch.
2494
self.assertLength(2, self.hpss_calls)
2496
def test_stacked_get_stream_topological(self):
2497
# Repository._get_source.get_stream() from a stacked repository with
2498
# topological sorting yields the full data from both stacked and
2499
# stacked upon sources in topological order.
2500
rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
2501
self.assertEqual(expected_revs, rev_ord)
2502
# Getting topological sort requires VFS calls still
2503
self.assertLength(12, self.hpss_calls)
2505
def test_stacked_get_stream_groupcompress(self):
2506
# Repository._get_source.get_stream() from a stacked repository with
2507
# groupcompress sorting yields the full data from both stacked and
2508
# stacked upon sources in groupcompress order.
2509
raise tests.TestSkipped('No groupcompress ordered format available')
2510
rev_ord, expected_revs = self.get_ordered_revs('dev5', 'groupcompress')
2511
self.assertEqual(expected_revs, reversed(rev_ord))
2512
# Getting unordered results should have made a streaming data request
2513
# from the backing branch, and one from the stacked on branch.
2514
self.assertLength(2, self.hpss_calls)
1928
2517
class TestRemoteBranchEffort(tests.TestCaseWithTransport):