1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
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
56
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
57
56
from bzrlib.revision import NULL_REVISION
58
from bzrlib.smart import medium
57
from bzrlib.smart import server, medium
59
58
from bzrlib.smart.client import _SmartClient
60
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
61
60
from bzrlib.tests import (
62
61
condition_isinstance,
63
62
split_suite_by_condition,
65
from bzrlib.transport import get_transport
67
66
from bzrlib.transport.memory import MemoryTransport
68
67
from bzrlib.transport.remote import (
76
75
standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
76
smart_server_version_scenarios = [
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
78
{'transport_server': server.SmartTCPServer_for_testing_v2_only}),
81
{'transport_server': test_server.SmartTCPServer_for_testing})]
80
{'transport_server': server.SmartTCPServer_for_testing})]
82
81
return multiply_tests(to_adapt, smart_server_version_scenarios, result)
89
88
self.transport = self.get_transport()
90
89
# make a branch that can be opened over the smart transport
91
90
self.local_wt = BzrDir.create_standalone_workingtree('.')
92
self.addCleanup(self.transport.disconnect)
93
self.transport.disconnect()
94
tests.TestCaseWithTransport.tearDown(self)
94
96
def test_create_remote_bzrdir(self):
95
97
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
132
134
b = BzrDir.open_from_transport(self.transport).open_branch()
133
135
self.assertStartsWith(str(b), 'RemoteBranch(')
135
def test_remote_bzrdir_repr(self):
136
b = BzrDir.open_from_transport(self.transport)
137
self.assertStartsWith(str(b), 'RemoteBzrDir(')
139
137
def test_remote_branch_format_supports_stacking(self):
140
138
t = self.transport
141
139
self.make_branch('unstackable', format='pack-0.92')
356
354
a given client_base and transport_base.
358
356
client_medium = medium.SmartClientMedium(client_base)
359
t = transport.get_transport(transport_base)
360
result = client_medium.remote_path_from_transport(t)
357
transport = get_transport(transport_base)
358
result = client_medium.remote_path_from_transport(transport)
361
359
self.assertEqual(expected, result)
363
361
def test_remote_path_from_transport(self):
374
372
a given transport_base and relpath of that transport. (Note that
375
373
HttpTransportBase is a subclass of SmartClientMedium)
377
base_transport = transport.get_transport(transport_base)
375
base_transport = get_transport(transport_base)
378
376
client_medium = base_transport.get_smart_medium()
379
377
cloned_transport = base_transport.clone(relpath)
380
378
result = client_medium.remote_path_from_transport(cloned_transport)
415
413
# Calling _remember_remote_is_before again with a lower value works.
416
414
client_medium._remember_remote_is_before((1, 5))
417
415
self.assertTrue(client_medium._is_remote_before((1, 5)))
418
# If you call _remember_remote_is_before with a higher value it logs a
419
# warning, and continues to remember the lower value.
420
self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
421
client_medium._remember_remote_is_before((1, 9))
422
self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
423
self.assertTrue(client_medium._is_remote_before((1, 5)))
416
# You cannot call _remember_remote_is_before with a larger value.
418
AssertionError, client_medium._remember_remote_is_before, (1, 9))
426
421
class TestBzrDirCloningMetaDir(TestRemote):
445
440
'BzrDir.cloning_metadir', ('quack/', 'False'),
446
441
'error', ('BranchReference',)),
447
442
client.add_expected_call(
448
'BzrDir.open_branchV3', ('quack/',),
443
'BzrDir.open_branchV2', ('quack/',),
449
444
'success', ('ref', self.get_url('referenced'))),
450
445
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
528
523
self.assertIsInstance(bd, RemoteBzrDir)
529
524
self.assertFinished(client)
531
def test_backwards_compat_hpss_v2(self):
532
client, transport = self.make_fake_client_and_transport()
533
# Monkey-patch fake client to simulate real-world behaviour with v2
534
# server: upon first RPC call detect the protocol version, and because
535
# the version is 2 also do _remember_remote_is_before((1, 6)) before
536
# continuing with the RPC.
537
orig_check_call = client._check_call
538
def check_call(method, args):
539
client._medium._protocol_version = 2
540
client._medium._remember_remote_is_before((1, 6))
541
client._check_call = orig_check_call
542
client._check_call(method, args)
543
client._check_call = check_call
544
client.add_expected_call(
545
'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
546
client.add_expected_call(
547
'BzrDir.open', ('quack/',), 'success', ('yes',))
548
bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
549
_client=client, _force_probe=True)
550
self.assertIsInstance(bd, RemoteBzrDir)
551
self.assertFinished(client)
554
527
class TestBzrDirOpenBranch(TestRemote):
558
531
self.make_branch('.')
559
532
a_dir = BzrDir.open(self.get_url('.'))
560
533
self.reset_smart_call_log()
561
verb = 'BzrDir.open_branchV3'
534
verb = 'BzrDir.open_branchV2'
562
535
self.disable_verb(verb)
563
536
format = a_dir.open_branch()
564
537
call_count = len([call for call in self.hpss_calls if
574
547
transport = transport.clone('quack')
575
548
client = FakeClient(transport.base)
576
549
client.add_expected_call(
577
'BzrDir.open_branchV3', ('quack/',),
550
'BzrDir.open_branchV2', ('quack/',),
578
551
'success', ('branch', branch_network_name))
579
552
client.add_expected_call(
580
553
'BzrDir.find_repositoryV3', ('quack/',),
600
573
self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
601
574
self.assertEqual(
602
[('call', 'BzrDir.open_branchV3', ('quack/',))],
575
[('call', 'BzrDir.open_branchV2', ('quack/',))],
605
578
def test__get_tree_branch(self):
606
579
# _get_tree_branch is a form of open_branch, but it should only ask for
607
580
# branch opening, not any other network requests.
609
def open_branch(name=None):
610
583
calls.append("Called")
611
584
return "a-branch"
612
585
transport = MemoryTransport()
629
602
network_name = reference_format.network_name()
630
603
branch_network_name = self.get_branch_format().network_name()
631
604
client.add_expected_call(
632
'BzrDir.open_branchV3', ('~hello/',),
605
'BzrDir.open_branchV2', ('~hello/',),
633
606
'success', ('branch', branch_network_name))
634
607
client.add_expected_call(
635
608
'BzrDir.find_repositoryV3', ('~hello/',),
1217
1190
client = FakeClient(self.get_url())
1218
1191
branch_network_name = self.get_branch_format().network_name()
1219
1192
client.add_expected_call(
1220
'BzrDir.open_branchV3', ('stacked/',),
1193
'BzrDir.open_branchV2', ('stacked/',),
1221
1194
'success', ('branch', branch_network_name))
1222
1195
client.add_expected_call(
1223
1196
'BzrDir.find_repositoryV3', ('stacked/',),
1245
1218
len(branch.repository._real_repository._fallback_repositories))
1247
1220
def test_get_stacked_on_real_branch(self):
1248
base_branch = self.make_branch('base')
1249
stacked_branch = self.make_branch('stacked')
1221
base_branch = self.make_branch('base', format='1.6')
1222
stacked_branch = self.make_branch('stacked', format='1.6')
1250
1223
stacked_branch.set_stacked_on_url('../base')
1251
1224
reference_format = self.get_repo_format()
1252
1225
network_name = reference_format.network_name()
1253
1226
client = FakeClient(self.get_url())
1254
1227
branch_network_name = self.get_branch_format().network_name()
1255
1228
client.add_expected_call(
1256
'BzrDir.open_branchV3', ('stacked/',),
1229
'BzrDir.open_branchV2', ('stacked/',),
1257
1230
'success', ('branch', branch_network_name))
1258
1231
client.add_expected_call(
1259
1232
'BzrDir.find_repositoryV3', ('stacked/',),
1260
'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1233
'success', ('ok', '', 'no', 'no', 'yes', network_name))
1261
1234
# called twice, once from constructor and then again by us
1262
1235
client.add_expected_call(
1263
1236
'Branch.get_stacked_on_url', ('stacked/',),
1615
1588
def test_get_multi_line_branch_conf(self):
1616
1589
# Make sure that multiple-line branch.conf files are supported
1618
# https://bugs.launchpad.net/bzr/+bug/354075
1591
# https://bugs.edge.launchpad.net/bzr/+bug/354075
1619
1592
client = FakeClient()
1620
1593
client.add_expected_call(
1621
1594
'Branch.get_stacked_on_url', ('memory:///',),
1649
1622
branch.unlock()
1650
1623
self.assertFinished(client)
1652
def test_set_option_with_dict(self):
1653
client = FakeClient()
1654
client.add_expected_call(
1655
'Branch.get_stacked_on_url', ('memory:///',),
1656
'error', ('NotStacked',),)
1657
client.add_expected_call(
1658
'Branch.lock_write', ('memory:///', '', ''),
1659
'success', ('ok', 'branch token', 'repo token'))
1660
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1661
client.add_expected_call(
1662
'Branch.set_config_option_dict', ('memory:///', 'branch token',
1663
'repo token', encoded_dict_value, 'foo', ''),
1665
client.add_expected_call(
1666
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1668
transport = MemoryTransport()
1669
branch = self.make_remote_branch(transport, client)
1671
config = branch._get_config()
1673
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1676
self.assertFinished(client)
1678
1625
def test_backwards_compat_set_option(self):
1679
1626
self.setup_smart_server_with_call_log()
1680
1627
branch = self.make_branch('.')
1687
1634
self.assertLength(10, self.hpss_calls)
1688
1635
self.assertEqual('value', branch._get_config().get_option('name'))
1690
def test_backwards_compat_set_option_with_dict(self):
1691
self.setup_smart_server_with_call_log()
1692
branch = self.make_branch('.')
1693
verb = 'Branch.set_config_option_dict'
1694
self.disable_verb(verb)
1696
self.addCleanup(branch.unlock)
1697
self.reset_smart_call_log()
1698
config = branch._get_config()
1699
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1700
config.set_option(value_dict, 'name')
1701
self.assertLength(10, self.hpss_calls)
1702
self.assertEqual(value_dict, branch._get_config().get_option('name'))
1705
1638
class TestBranchLockWrite(RemoteBranchTestCase):
2071
2004
self.assertLength(1, self.hpss_calls)
2073
2006
def disableExtraResults(self):
2074
self.overrideAttr(SmartServerRepositoryGetParentMap,
2075
'no_extra_results', True)
2007
old_flag = SmartServerRepositoryGetParentMap.no_extra_results
2008
SmartServerRepositoryGetParentMap.no_extra_results = True
2010
SmartServerRepositoryGetParentMap.no_extra_results = old_flag
2011
self.addCleanup(reset_values)
2077
2013
def test_null_cached_missing_and_stop_key(self):
2078
2014
self.setup_smart_server_with_call_log()
2138
2074
def test_allows_new_revisions(self):
2139
2075
"""get_parent_map's results can be updated by commit."""
2140
smart_server = test_server.SmartTCPServer_for_testing()
2076
smart_server = server.SmartTCPServer_for_testing()
2141
2077
self.start_server(smart_server)
2142
2078
self.make_branch('branch')
2143
2079
branch = Branch.open(smart_server.get_url() + '/branch')
2254
2190
# Make a repo with a fallback repo, both using a FakeClient.
2255
2191
format = remote.response_tuple_to_repo_format(
2256
('yes', 'no', 'yes', self.get_repo_format().network_name()))
2192
('yes', 'no', 'yes', 'fake-network-name'))
2257
2193
repo, client = self.setup_fake_client_and_repository('quack')
2258
2194
repo._format = format
2259
2195
fallback_repo, ignored = self.setup_fake_client_and_repository(
2261
2197
fallback_repo._client = client
2262
fallback_repo._format = format
2263
2198
repo.add_fallback_repository(fallback_repo)
2264
2199
# First the client should ask the primary repo
2265
2200
client.add_expected_call(
2339
2273
transport_path = 'quack'
2340
2274
repo, client = self.setup_fake_client_and_repository(transport_path)
2341
2275
client.add_success_response('ok', 'a token')
2342
token = repo.lock_write().repository_token
2276
result = repo.lock_write()
2343
2277
self.assertEqual(
2344
2278
[('call', 'Repository.lock_write', ('quack/', ''))],
2346
self.assertEqual('a token', token)
2280
self.assertEqual('a token', result)
2348
2282
def test_lock_write_already_locked(self):
2349
2283
transport_path = 'quack'
2687
2621
"""RemoteRepository.copy_content_into optimizations"""
2689
2623
def test_copy_content_remote_to_local(self):
2690
self.transport_server = test_server.SmartTCPServer_for_testing
2624
self.transport_server = server.SmartTCPServer_for_testing
2691
2625
src_repo = self.make_repository('repo1')
2692
2626
src_repo = repository.Repository.open(self.get_url('repo1'))
2693
2627
# At the moment the tarball-based copy_content_into can't write back
2841
2775
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2842
2776
self.assertEqual(expected_error, translated_error)
2844
def test_nobranch_one_arg(self):
2845
bzrdir = self.make_bzrdir('')
2846
translated_error = self.translateTuple(
2847
('nobranch', 'extra detail'), bzrdir=bzrdir)
2848
expected_error = errors.NotBranchError(
2849
path=bzrdir.root_transport.base,
2850
detail='extra detail')
2851
self.assertEqual(expected_error, translated_error)
2853
2778
def test_LockContention(self):
2854
2779
translated_error = self.translateTuple(('LockContention',))
2855
2780
expected_error = errors.LockContention('(remote lock)')
2968
2893
# In addition to re-raising ErrorFromSmartServer, some debug info has
2969
2894
# been muttered to the log file for developer to look at.
2970
2895
self.assertContainsRe(
2896
self._get_log(keep_log_file=True),
2972
2897
"Missing key 'branch' in context")
2974
2899
def test_path_missing(self):
2982
2907
self.assertEqual(server_error, translated_error)
2983
2908
# In addition to re-raising ErrorFromSmartServer, some debug info has
2984
2909
# been muttered to the log file for developer to look at.
2985
self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
2910
self.assertContainsRe(
2911
self._get_log(keep_log_file=True), "Missing key 'path' in context")
2988
2914
class TestStacking(tests.TestCaseWithTransport):
3006
2932
stacked_branch = self.make_branch('stacked', format='1.9')
3007
2933
stacked_branch.set_stacked_on_url('../base')
3008
2934
# start a server looking at this
3009
smart_server = test_server.SmartTCPServer_for_testing()
2935
smart_server = server.SmartTCPServer_for_testing()
3010
2936
self.start_server(smart_server)
3011
2937
remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
3012
2938
# can get its branch and repository
3168
3094
super(TestRemoteBranchEffort, self).setUp()
3169
3095
# Create a smart server that publishes whatever the backing VFS server
3171
self.smart_server = test_server.SmartTCPServer_for_testing()
3097
self.smart_server = server.SmartTCPServer_for_testing()
3172
3098
self.start_server(self.smart_server, self.get_server())
3173
3099
# Log all HPSS calls into self.hpss_calls.
3174
3100
_SmartClient.hooks.install_named_hook(